Command line static remapping (#217)
Command line static remapping (ROS1 compatible syntax + nodename prefix)
This commit is contained in:
parent
7008a7d6e7
commit
3628967496
20 changed files with 2550 additions and 91 deletions
|
@ -27,6 +27,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(${PROJECT_NAME}_sources
|
set(${PROJECT_NAME}_sources
|
||||||
|
src/rcl/arguments.c
|
||||||
src/rcl/client.c
|
src/rcl/client.c
|
||||||
src/rcl/common.c
|
src/rcl/common.c
|
||||||
src/rcl/expand_topic_name.c
|
src/rcl/expand_topic_name.c
|
||||||
|
@ -35,6 +36,7 @@ set(${PROJECT_NAME}_sources
|
||||||
src/rcl/node.c
|
src/rcl/node.c
|
||||||
src/rcl/publisher.c
|
src/rcl/publisher.c
|
||||||
src/rcl/rcl.c
|
src/rcl/rcl.c
|
||||||
|
src/rcl/remap.c
|
||||||
src/rcl/rmw_implementation_identifier_check.c
|
src/rcl/rmw_implementation_identifier_check.c
|
||||||
src/rcl/service.c
|
src/rcl/service.c
|
||||||
src/rcl/subscription.c
|
src/rcl/subscription.c
|
||||||
|
|
187
rcl/include/rcl/arguments.h
Normal file
187
rcl/include/rcl/arguments.h
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
// Copyright 2018 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCL__ARGUMENTS_H_
|
||||||
|
#define RCL__ARGUMENTS_H_
|
||||||
|
|
||||||
|
#include "rcl/allocator.h"
|
||||||
|
#include "rcl/macros.h"
|
||||||
|
#include "rcl/types.h"
|
||||||
|
#include "rcl/visibility_control.h"
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct rcl_arguments_impl_t;
|
||||||
|
|
||||||
|
/// Hold output of parsing command line arguments.
|
||||||
|
typedef struct rcl_arguments_t
|
||||||
|
{
|
||||||
|
/// Private implementation pointer.
|
||||||
|
struct rcl_arguments_impl_t * impl;
|
||||||
|
} rcl_arguments_t;
|
||||||
|
|
||||||
|
/// Return a rcl_node_t struct with members initialized to `NULL`.
|
||||||
|
RCL_PUBLIC
|
||||||
|
RCL_WARN_UNUSED
|
||||||
|
rcl_arguments_t
|
||||||
|
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`.
|
||||||
|
* \sa rcl_arguments_get_count_unparsed()
|
||||||
|
* \sa rcl_arguments_get_unparsed()
|
||||||
|
*
|
||||||
|
* Successfully parsed remap rules are stored in the order they were given in `argv`.
|
||||||
|
* If given arguments `{"__ns:=/foo", "__ns:=/bar"}` then the namespace used by nodes in this
|
||||||
|
* process will be `/foo` and not `/bar`.
|
||||||
|
* \sa rcl_remap_topic_name()
|
||||||
|
* \sa rcl_remap_service_name()
|
||||||
|
* \sa rcl_remap_node_name()
|
||||||
|
* \sa rcl_remap_node_namespace()
|
||||||
|
*
|
||||||
|
* <hr>
|
||||||
|
* Attribute | Adherence
|
||||||
|
* ------------------ | -------------
|
||||||
|
* Allocates Memory | Yes
|
||||||
|
* Thread-Safe | Yes
|
||||||
|
* Uses Atomics | No
|
||||||
|
* Lock-Free | Yes
|
||||||
|
*
|
||||||
|
* \param[in] argc The number of arguments in argv.
|
||||||
|
* \param[in] argv Whe values of the arguments.
|
||||||
|
* \param[in] allocator A valid allocator.
|
||||||
|
* \param[out] args_output A structure that will contain the result of parsing.
|
||||||
|
* \return `RCL_RET_OK` if the arguments were parsed successfully, 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_parse_arguments(
|
||||||
|
int argc,
|
||||||
|
const char * const argv[],
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
rcl_arguments_t * args_output);
|
||||||
|
|
||||||
|
/// Return the number of arguments that were not successfully parsed.
|
||||||
|
/**
|
||||||
|
* <hr>
|
||||||
|
* Attribute | Adherence
|
||||||
|
* ------------------ | -------------
|
||||||
|
* Allocates Memory | No
|
||||||
|
* Thread-Safe | Yes
|
||||||
|
* Uses Atomics | No
|
||||||
|
* Lock-Free | Yes
|
||||||
|
*
|
||||||
|
* \param[in] args An arguments structure that has been parsed.
|
||||||
|
* \return number of unparsed arguments, or
|
||||||
|
* \return -1 if args is `NULL` or zero initialized.
|
||||||
|
*/
|
||||||
|
RCL_PUBLIC
|
||||||
|
RCL_WARN_UNUSED
|
||||||
|
int
|
||||||
|
rcl_arguments_get_count_unparsed(
|
||||||
|
rcl_arguments_t * args);
|
||||||
|
|
||||||
|
/// Return a list of indexes that weren't successfully parsed.
|
||||||
|
/**
|
||||||
|
* Some arguments may not have been successfully parsed, or were not intended as ROS arguments.
|
||||||
|
* This function populates an array of indexes to these arguments in the original argv array.
|
||||||
|
* Since the first argument is always assumed to be a process name, the list will always contain
|
||||||
|
* the index 0.
|
||||||
|
*
|
||||||
|
* <hr>
|
||||||
|
* Attribute | Adherence
|
||||||
|
* ------------------ | -------------
|
||||||
|
* Allocates Memory | Yes
|
||||||
|
* Thread-Safe | Yes
|
||||||
|
* Uses Atomics | No
|
||||||
|
* Lock-Free | Yes
|
||||||
|
*
|
||||||
|
* \param[in] args An arguments structure that has been parsed.
|
||||||
|
* \param[in] allocator A valid allocator.
|
||||||
|
* \param[out] output_unparsed_indices An allocated array of indices into the original argv array.
|
||||||
|
* This array must be deallocated by the caller using the given allocator.
|
||||||
|
* If there are no unparsed 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_arguments_get_unparsed(
|
||||||
|
rcl_arguments_t * args,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
int ** output_unparsed_indices);
|
||||||
|
|
||||||
|
/// Reclaim resources held inside rcl_arguments_t structure.
|
||||||
|
/**
|
||||||
|
* <hr>
|
||||||
|
* Attribute | Adherence
|
||||||
|
* ------------------ | -------------
|
||||||
|
* Allocates Memory | No
|
||||||
|
* Thread-Safe | Yes
|
||||||
|
* Uses Atomics | No
|
||||||
|
* Lock-Free | Yes
|
||||||
|
*
|
||||||
|
* \param[in] args The structure to be deallocated.
|
||||||
|
* \param[in] allocator A valid allocator.
|
||||||
|
* \return `RCL_RET_OK` if the memory was successfully freed, 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_arguments_fini(
|
||||||
|
rcl_arguments_t * args);
|
||||||
|
|
||||||
|
/// Get a global instance of command line arguments.
|
||||||
|
/**
|
||||||
|
* \sa rcl_init(int, char **, rcl_allocator_t)
|
||||||
|
* \sa rcl_shutdown()
|
||||||
|
* This returns parsed command line arguments that were passed to `rcl_init()`.
|
||||||
|
* The value returned by this function is undefined before `rcl_init()` is called and after
|
||||||
|
* `rcl_shutdown()` is called.
|
||||||
|
* The return value must not be finalized.
|
||||||
|
*
|
||||||
|
* <hr>
|
||||||
|
* Attribute | Adherence
|
||||||
|
* ------------------ | -------------
|
||||||
|
* Allocates Memory | No
|
||||||
|
* Thread-Safe | Yes
|
||||||
|
* Uses Atomics | No
|
||||||
|
* Lock-Free | Yes
|
||||||
|
*
|
||||||
|
* \return a global instance of parsed command line arguments.
|
||||||
|
*/
|
||||||
|
RCL_PUBLIC
|
||||||
|
RCL_WARN_UNUSED
|
||||||
|
rcl_arguments_t *
|
||||||
|
rcl_get_global_arguments();
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RCL__ARGUMENTS_H_
|
|
@ -23,6 +23,7 @@ extern "C"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "rcl/allocator.h"
|
#include "rcl/allocator.h"
|
||||||
|
#include "rcl/arguments.h"
|
||||||
#include "rcl/macros.h"
|
#include "rcl/macros.h"
|
||||||
#include "rcl/types.h"
|
#include "rcl/types.h"
|
||||||
#include "rcl/visibility_control.h"
|
#include "rcl/visibility_control.h"
|
||||||
|
@ -65,6 +66,12 @@ typedef struct rcl_node_options_t
|
||||||
|
|
||||||
/// Custom allocator used for internal allocations.
|
/// Custom allocator used for internal allocations.
|
||||||
rcl_allocator_t allocator;
|
rcl_allocator_t allocator;
|
||||||
|
|
||||||
|
/// If false then only use arguments in this struct, otherwise use global arguments also.
|
||||||
|
bool use_global_arguments;
|
||||||
|
|
||||||
|
/// Command line arguments that apply only to this node.
|
||||||
|
rcl_arguments_t arguments;
|
||||||
} rcl_node_options_t;
|
} rcl_node_options_t;
|
||||||
|
|
||||||
/// Return a rcl_node_t struct with members initialized to `NULL`.
|
/// Return a rcl_node_t struct with members initialized to `NULL`.
|
||||||
|
|
239
rcl/include/rcl/remap.h
Normal file
239
rcl/include/rcl/remap.h
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
// Copyright 2018 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCL__REMAP_H_
|
||||||
|
#define RCL__REMAP_H_
|
||||||
|
|
||||||
|
#include "rcl/allocator.h"
|
||||||
|
#include "rcl/arguments.h"
|
||||||
|
#include "rcl/macros.h"
|
||||||
|
#include "rcl/types.h"
|
||||||
|
#include "rcl/visibility_control.h"
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO(sloretz) add documentation about rostopic:// when it is supported
|
||||||
|
/// Remap a topic name based on given rules.
|
||||||
|
/**
|
||||||
|
* The supplied topic name must have already been expanded to a fully qualified name.
|
||||||
|
* \sa rcl_expand_topic_name()
|
||||||
|
*
|
||||||
|
* If `local_arguments` is not NULL and not zero intialized then its remap rules are checked first.
|
||||||
|
* If no rules matched and `global_arguments` is not NULL and not zero intitialized then its rules
|
||||||
|
* are checked next.
|
||||||
|
* If both `local_arguments` and global_arguments are NULL or zero intialized then the function will
|
||||||
|
* return RCL_RET_INVALID_ARGUMENT.
|
||||||
|
*
|
||||||
|
* `global_arguments` is usually the arguments passed to `rcl_init()`.
|
||||||
|
* \sa rcl_init()
|
||||||
|
* \sa rcl_get_global_arguments()
|
||||||
|
*
|
||||||
|
* Remap rules are checked in the order they were given.
|
||||||
|
* For rules passed to `rcl_init` this usually is the order they were passed on the command line.
|
||||||
|
* \sa rcl_parse_arguments()
|
||||||
|
*
|
||||||
|
* Only the first remap rule that matches is used to remap a name.
|
||||||
|
* For example, if the command line arguments are `foo:=bar bar:=baz` the topic `foo` is remapped to
|
||||||
|
* `bar` and not `baz`.
|
||||||
|
*
|
||||||
|
* `node_name` and `node_namespace` are used to expand the match and replacement into fully
|
||||||
|
* qualified names.
|
||||||
|
* Given node_name `trudy`, namespace `/ns`, and rule `foo:=~/bar` the names in the rule are
|
||||||
|
* expanded to `/ns/foo:=/ns/trudy/bar`.
|
||||||
|
* The rule will only apply if the given topic name is `/ns/foo`.
|
||||||
|
*
|
||||||
|
* `node_name` is also used to match against node specific rules.
|
||||||
|
* Given rules `alice:foo:=bar foo:=baz`, node name `alice`, and topic `foo` the remapped topic
|
||||||
|
* name will be `bar`.
|
||||||
|
* If given the node name `bob` and topic `foo` the remaped topic name would be `baz` instead.
|
||||||
|
* Note that processing always stops at the first matching rule even if there is a more specific one
|
||||||
|
* later on.
|
||||||
|
* Given `foo:=bar alice:foo:=baz` and topic name `foo` the remapped topic name will always be
|
||||||
|
* `bar` regardless of the node name given.
|
||||||
|
*
|
||||||
|
* <hr>
|
||||||
|
* Attribute | Adherence
|
||||||
|
* ------------------ | -------------
|
||||||
|
* Allocates Memory | Yes
|
||||||
|
* Thread-Safe | No
|
||||||
|
* Uses Atomics | No
|
||||||
|
* Lock-Free | Yes
|
||||||
|
*
|
||||||
|
* \param[in] local_arguments Command line arguments to be used before global arguments, or
|
||||||
|
* if NULL or zero-initialized then only global arguments are used.
|
||||||
|
* \param[in] global_arguments Command line arguments to use if no local rules matched, or
|
||||||
|
* `NULL` or zero-initialized to ignore global arguments.
|
||||||
|
* \param[in] topic_name A fully qualified and expanded topic name to be remapped.
|
||||||
|
* \param[in] node_name The name of the node to which name belongs.
|
||||||
|
* \param[in] node_namespace The namespace of a node to which name belongs.
|
||||||
|
* \param[in] allocator A valid allocator to use.
|
||||||
|
* \param[out] output_name Either an allocated string with the remapped name, or
|
||||||
|
* `NULL` if no remap rules matched the name.
|
||||||
|
* \return `RCL_RET_OK` if the topic name was remapped or no rules matched, or
|
||||||
|
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
|
||||||
|
* \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
|
||||||
|
* \return `RCL_RET_TOPIC_NAME_INVALID` if the given topic name is invalid, or
|
||||||
|
* \return `RCL_RET_ERROR` if an unspecified error occurs.
|
||||||
|
*/
|
||||||
|
RCL_PUBLIC
|
||||||
|
RCL_WARN_UNUSED
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_remap_topic_name(
|
||||||
|
const rcl_arguments_t * local_arguments,
|
||||||
|
const rcl_arguments_t * global_arguments,
|
||||||
|
const char * topic_name,
|
||||||
|
const char * node_name,
|
||||||
|
const char * node_namespace,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
char ** output_name);
|
||||||
|
|
||||||
|
// TODO(sloretz) add documentation about rosservice:// when it is supported
|
||||||
|
/// Remap a service name based on given rules.
|
||||||
|
/**
|
||||||
|
* The supplied service name must have already been expanded to a fully qualified name.
|
||||||
|
*
|
||||||
|
* The behavior of this function is identical to rcl_expand_topic_name() except that it applies
|
||||||
|
* to service names instead of topic names.
|
||||||
|
* \sa rcl_expand_topic_name()
|
||||||
|
*
|
||||||
|
* <hr>
|
||||||
|
* Attribute | Adherence
|
||||||
|
* ------------------ | -------------
|
||||||
|
* Allocates Memory | Yes
|
||||||
|
* Thread-Safe | No
|
||||||
|
* Uses Atomics | No
|
||||||
|
* Lock-Free | Yes
|
||||||
|
*
|
||||||
|
* \param[in] local_arguments Command line arguments to be used before global arguments, or
|
||||||
|
* if NULL or zero-initialized then only global arguments are used.
|
||||||
|
* \param[in] global_arguments Command line arguments to use if no local rules matched, or
|
||||||
|
* `NULL` or zero-initialized to ignore global arguments.
|
||||||
|
* \param[in] service_name A fully qualified and expanded service name to be remapped.
|
||||||
|
* \param[in] node_name The name of the node to which name belongs.
|
||||||
|
* \param[in] node_namespace The namespace of a node to which name belongs.
|
||||||
|
* \param[in] allocator A valid allocator to use.
|
||||||
|
* \param[out] output_name Either an allocated string with the remapped name, or
|
||||||
|
* `NULL` if no remap rules matched the name.
|
||||||
|
* \return `RCL_RET_OK` if the name was remapped or no rules matched, or
|
||||||
|
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
|
||||||
|
* \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
|
||||||
|
* \return `RCL_RET_SERVICE_NAME_INVALID` if the given name is invalid, or
|
||||||
|
* \return `RCL_RET_ERROR` if an unspecified error occurs.
|
||||||
|
*/
|
||||||
|
RCL_PUBLIC
|
||||||
|
RCL_WARN_UNUSED
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_remap_service_name(
|
||||||
|
const rcl_arguments_t * local_arguments,
|
||||||
|
const rcl_arguments_t * global_arguments,
|
||||||
|
const char * serivice_name,
|
||||||
|
const char * node_name,
|
||||||
|
const char * node_namespace,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
char ** output_name);
|
||||||
|
|
||||||
|
/// Remap a node name based on given rules.
|
||||||
|
/**
|
||||||
|
* This function returns the node name that a node with the given name would be remapped to.
|
||||||
|
* When a node's name is remapped it changes its logger name and the output of expanding relative
|
||||||
|
* topic and service names.
|
||||||
|
*
|
||||||
|
* When composing nodes make sure that the final node names used are unique per process.
|
||||||
|
* There is not currently a way to independently remap the names of two nodes that were created
|
||||||
|
* with the same node name and are manually composed into one process.
|
||||||
|
*
|
||||||
|
* The behavior of `local_arguments`, `global_arguments`, `node_name`, the order remap rules are
|
||||||
|
* applied, and node specific rules is identical to rcl_remap_topic_name().
|
||||||
|
* \sa rcl_remap_topic_name()
|
||||||
|
*
|
||||||
|
* <hr>
|
||||||
|
* Attribute | Adherence
|
||||||
|
* ------------------ | -------------
|
||||||
|
* Allocates Memory | Yes
|
||||||
|
* Thread-Safe | No
|
||||||
|
* Uses Atomics | No
|
||||||
|
* Lock-Free | Yes
|
||||||
|
*
|
||||||
|
* \param[in] local_arguments Arguments to be used before global arguments.
|
||||||
|
* \param[in] global_arguments Command line arguments to use if no local rules matched, or
|
||||||
|
* `NULL` or zero-initialized to ignore global arguments.
|
||||||
|
* \param[in] node_name The current name of the node.
|
||||||
|
* \param[in] allocator A valid allocator to use.
|
||||||
|
* \param[out] output_name Either an allocated string with the remapped name, or
|
||||||
|
* `NULL` if no remap rules matched the name.
|
||||||
|
* \return `RCL_RET_OK` If the name was remapped or no rules matched, or
|
||||||
|
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
|
||||||
|
* \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
|
||||||
|
* \return `RCL_RET_NODE_INVALID_NAME` if the name is invalid, or
|
||||||
|
* \return `RCL_RET_ERROR` if an unspecified error occurs.
|
||||||
|
*/
|
||||||
|
RCL_PUBLIC
|
||||||
|
RCL_WARN_UNUSED
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_remap_node_name(
|
||||||
|
const rcl_arguments_t * local_arguments,
|
||||||
|
const rcl_arguments_t * global_arguments,
|
||||||
|
const char * node_name,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
char ** output_name);
|
||||||
|
|
||||||
|
/// Remap a namespace based on given rules.
|
||||||
|
/**
|
||||||
|
* This function returns the namespace that a node with the given name would be remapped to.
|
||||||
|
* When a node's namespace is remapped it changes its logger name and the output of expanding
|
||||||
|
* relative topic and service names.
|
||||||
|
*
|
||||||
|
* The behavior of `local_arguments`, `global_arguments`, `node_name`, the order remap rules are
|
||||||
|
* applied, and node specific rules is identical to rcl_remap_topic_name().
|
||||||
|
* \sa rcl_remap_topic_name()
|
||||||
|
*
|
||||||
|
* <hr>
|
||||||
|
* Attribute | Adherence
|
||||||
|
* ------------------ | -------------
|
||||||
|
* Allocates Memory | Yes
|
||||||
|
* Thread-Safe | No
|
||||||
|
* Uses Atomics | No
|
||||||
|
* Lock-Free | Yes
|
||||||
|
*
|
||||||
|
* \param[in] local_arguments Arguments to be used before global arguments.
|
||||||
|
* \param[in] global_arguments Command line arguments to use if no local rules matched, or
|
||||||
|
* `NULL` or zero-initialized to ignore global arguments.
|
||||||
|
* \param[in] node_name The name of the node whose namespace is being remapped.
|
||||||
|
* \param[in] allocator A valid allocator to be used.
|
||||||
|
* \param[out] output_namespace Either an allocated string with the remapped namespace, or
|
||||||
|
* `NULL` if no remap rules matched the name.
|
||||||
|
* \return `RCL_RET_OK` if the node name was remapped or no rules matched, or
|
||||||
|
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
|
||||||
|
* \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
|
||||||
|
* \return `RCL_RET_NODE_INVALID_NAMESPACE` if the remapped namespace is invalid, or
|
||||||
|
* \return `RCL_RET_ERROR` if an unspecified error occurs.
|
||||||
|
*/
|
||||||
|
RCL_PUBLIC
|
||||||
|
RCL_WARN_UNUSED
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_remap_node_namespace(
|
||||||
|
const rcl_arguments_t * local_arguments,
|
||||||
|
const rcl_arguments_t * global_arguments,
|
||||||
|
const char * node_name,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
char ** output_namespace);
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RCL__REMAP_H_
|
|
@ -87,4 +87,8 @@ typedef rmw_ret_t rcl_ret_t;
|
||||||
/// Given rcl_wait_set_t is full return code.
|
/// Given rcl_wait_set_t is full return code.
|
||||||
#define RCL_RET_WAIT_SET_FULL 902
|
#define RCL_RET_WAIT_SET_FULL 902
|
||||||
|
|
||||||
|
// rcl argument parsing specific ret codes in 1XXX
|
||||||
|
/// Argument is not a valid remap rule
|
||||||
|
#define RCL_RET_INVALID_REMAP_RULE 1001
|
||||||
|
|
||||||
#endif // RCL__TYPES_H_
|
#endif // RCL__TYPES_H_
|
||||||
|
|
403
rcl/src/rcl/arguments.c
Normal file
403
rcl/src/rcl/arguments.c
Normal file
|
@ -0,0 +1,403 @@
|
||||||
|
// Copyright 2018 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "rcl/arguments.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "./arguments_impl.h"
|
||||||
|
#include "./remap_impl.h"
|
||||||
|
#include "rcl/error_handling.h"
|
||||||
|
#include "rcl/validate_topic_name.h"
|
||||||
|
#include "rcutils/allocator.h"
|
||||||
|
#include "rcutils/logging_macros.h"
|
||||||
|
#include "rcutils/strdup.h"
|
||||||
|
#include "rmw/validate_namespace.h"
|
||||||
|
#include "rmw/validate_node_name.h"
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Instance of global arguments.
|
||||||
|
static rcl_arguments_t __rcl_global_arguments;
|
||||||
|
|
||||||
|
/// Parse an argument that may or may not be a remap rule.
|
||||||
|
/// \param[in] arg the argument to parse
|
||||||
|
/// \param[in] allocator an allocator to use
|
||||||
|
/// \param[in,out] output_rule input a zero intialized rule, output a fully initialized one
|
||||||
|
/// \return RCL_RET_OK if a valid rule was parsed, or
|
||||||
|
/// \return RCL_RET_INVALID_REMAP_RULE if the argument is not a valid rule, or
|
||||||
|
/// \return RCL_RET_BAD_ALLOC if an allocation failed, or
|
||||||
|
/// \return RLC_RET_ERROR if an unspecified error occurred.
|
||||||
|
/// \internal
|
||||||
|
RCL_LOCAL
|
||||||
|
rcl_ret_t
|
||||||
|
_rcl_parse_remap_rule(
|
||||||
|
const char * arg,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
rcl_remap_t * output_rule)
|
||||||
|
{
|
||||||
|
size_t len_node_name = 0;
|
||||||
|
size_t len_match = 0;
|
||||||
|
size_t len_replacement = 0;
|
||||||
|
|
||||||
|
const char * separator = NULL;
|
||||||
|
const char * colon = NULL;
|
||||||
|
const char * match_begin = arg;
|
||||||
|
const char * replacement_begin = NULL;
|
||||||
|
|
||||||
|
// A valid rule has two parts separated by :=
|
||||||
|
separator = strstr(arg, ":=");
|
||||||
|
if (NULL == separator) {
|
||||||
|
RCL_SET_ERROR_MSG("missing :=", allocator);
|
||||||
|
return RCL_RET_INVALID_REMAP_RULE;
|
||||||
|
}
|
||||||
|
|
||||||
|
replacement_begin = separator + 2;
|
||||||
|
|
||||||
|
// must have characters on both sides of the separator
|
||||||
|
len_match = separator - arg;
|
||||||
|
len_replacement = strlen(replacement_begin);
|
||||||
|
if (0 == len_match) {
|
||||||
|
RCL_SET_ERROR_MSG("match is zero length", allocator);
|
||||||
|
return RCL_RET_INVALID_REMAP_RULE;
|
||||||
|
} else if (0 == len_replacement) {
|
||||||
|
RCL_SET_ERROR_MSG("replacement has zero length", allocator);
|
||||||
|
return RCL_RET_INVALID_REMAP_RULE;
|
||||||
|
}
|
||||||
|
|
||||||
|
colon = strchr(arg, ':');
|
||||||
|
if (NULL != colon) {
|
||||||
|
if (colon < separator) {
|
||||||
|
// If there is a : on the match side then there is a node-name prefix
|
||||||
|
match_begin = colon + 1;
|
||||||
|
len_node_name = colon - arg;
|
||||||
|
len_match = separator - match_begin;
|
||||||
|
// node name must have at least one character
|
||||||
|
if (len_node_name <= 0) {
|
||||||
|
RCL_SET_ERROR_MSG("node name previx has zero length", allocator);
|
||||||
|
return RCL_RET_INVALID_REMAP_RULE;
|
||||||
|
}
|
||||||
|
} else if (colon > separator) {
|
||||||
|
// If the colon is on the replacement side then this couldn't be a valid rule
|
||||||
|
RCL_SET_ERROR_MSG("replacement side cannot contain a :", allocator);
|
||||||
|
return RCL_RET_INVALID_REMAP_RULE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maybe match length changed because there was a node name prefix
|
||||||
|
if (0 == len_match) {
|
||||||
|
RCL_SET_ERROR_MSG("match is zero length", allocator);
|
||||||
|
return RCL_RET_INVALID_REMAP_RULE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure node name contains only valid characters
|
||||||
|
if (len_node_name) {
|
||||||
|
int validation_result;
|
||||||
|
size_t invalid_index;
|
||||||
|
if (
|
||||||
|
RMW_RET_OK != rmw_validate_node_name_with_size(arg, len_node_name, &validation_result,
|
||||||
|
&invalid_index))
|
||||||
|
{
|
||||||
|
RCL_SET_ERROR_MSG("failed to run check on node name", allocator);
|
||||||
|
return RCL_RET_ERROR;
|
||||||
|
}
|
||||||
|
if (RMW_NODE_NAME_VALID != validation_result) {
|
||||||
|
RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
|
||||||
|
allocator,
|
||||||
|
"node name prefix invalid: %s", rmw_node_name_validation_result_string(validation_result));
|
||||||
|
return RCL_RET_INVALID_REMAP_RULE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out what type of rule this is, default is to apply to topic and service names
|
||||||
|
rcl_remap_type_t type = RCL_TOPIC_REMAP | RCL_SERVICE_REMAP;
|
||||||
|
if (0 == strncmp("__ns", match_begin, len_match)) {
|
||||||
|
type = RCL_NAMESPACE_REMAP;
|
||||||
|
} else if (0 == strncmp("__node", match_begin, len_match)) {
|
||||||
|
type = RCL_NODENAME_REMAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type & (RCL_TOPIC_REMAP | RCL_SERVICE_REMAP)) {
|
||||||
|
// Replacement must be a valid topic name
|
||||||
|
int validation_result;
|
||||||
|
size_t invalid_index;
|
||||||
|
rcl_ret_t ret = rcl_validate_topic_name(replacement_begin, &validation_result, &invalid_index);
|
||||||
|
if (ret != RCL_RET_OK) {
|
||||||
|
return RCL_RET_ERROR;
|
||||||
|
} else if (validation_result != RCL_TOPIC_NAME_VALID) {
|
||||||
|
RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
|
||||||
|
allocator,
|
||||||
|
"replacement is invalid: %s", rcl_topic_name_validation_result_string(validation_result));
|
||||||
|
return RCL_RET_INVALID_REMAP_RULE;
|
||||||
|
}
|
||||||
|
// Match must be a valid topic name
|
||||||
|
ret = rcl_validate_topic_name_with_size(
|
||||||
|
match_begin, len_match, &validation_result, &invalid_index);
|
||||||
|
if (ret != RCL_RET_OK) {
|
||||||
|
return RCL_RET_ERROR;
|
||||||
|
} else if (validation_result != RCL_TOPIC_NAME_VALID) {
|
||||||
|
RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
|
||||||
|
allocator,
|
||||||
|
"match is invalid: %s", rcl_topic_name_validation_result_string(validation_result));
|
||||||
|
return RCL_RET_INVALID_REMAP_RULE;
|
||||||
|
}
|
||||||
|
} else if (RCL_NAMESPACE_REMAP == type) {
|
||||||
|
int validation_result;
|
||||||
|
size_t invalid_idx;
|
||||||
|
if (RMW_RET_OK != rmw_validate_namespace(replacement_begin, &validation_result, &invalid_idx)) {
|
||||||
|
RCL_SET_ERROR_MSG("failed to run check on namespace", allocator);
|
||||||
|
return RCL_RET_ERROR;
|
||||||
|
}
|
||||||
|
if (RMW_NAMESPACE_VALID != validation_result) {
|
||||||
|
RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
|
||||||
|
allocator,
|
||||||
|
"namespace is invalid: %s", rmw_namespace_validation_result_string(validation_result));
|
||||||
|
return RCL_RET_INVALID_REMAP_RULE;
|
||||||
|
}
|
||||||
|
} else if (RCL_NODENAME_REMAP == type) {
|
||||||
|
int validation_result;
|
||||||
|
size_t invalid_idx;
|
||||||
|
if (RMW_RET_OK != rmw_validate_node_name(replacement_begin, &validation_result, &invalid_idx)) {
|
||||||
|
RCL_SET_ERROR_MSG("failed to run check on node name", allocator);
|
||||||
|
return RCL_RET_ERROR;
|
||||||
|
}
|
||||||
|
if (RMW_NODE_NAME_VALID != validation_result) {
|
||||||
|
RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
|
||||||
|
allocator,
|
||||||
|
"node name is invalid: %s", rmw_node_name_validation_result_string(validation_result));
|
||||||
|
return RCL_RET_INVALID_REMAP_RULE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rule is valid, construct a structure for it
|
||||||
|
output_rule->allocator = allocator;
|
||||||
|
output_rule->type = type;
|
||||||
|
if (len_node_name > 0) {
|
||||||
|
output_rule->node_name = rcutils_strndup(arg, len_node_name, allocator);
|
||||||
|
if (NULL == output_rule->node_name) {
|
||||||
|
goto cleanup_rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type & (RCL_TOPIC_REMAP | RCL_SERVICE_REMAP)) {
|
||||||
|
output_rule->match = rcutils_strndup(match_begin, len_match, allocator);
|
||||||
|
if (NULL == output_rule->match) {
|
||||||
|
goto cleanup_rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output_rule->replacement = rcutils_strndup(replacement_begin, len_replacement, allocator);
|
||||||
|
if (NULL == output_rule->replacement) {
|
||||||
|
goto cleanup_rule;
|
||||||
|
}
|
||||||
|
return RCL_RET_OK;
|
||||||
|
|
||||||
|
cleanup_rule:
|
||||||
|
if (RCL_RET_OK != rcl_remap_fini(output_rule)) {
|
||||||
|
RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "Failed to fini remap rule after error occurred");
|
||||||
|
}
|
||||||
|
return RCL_RET_BAD_ALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_parse_arguments(
|
||||||
|
int argc,
|
||||||
|
const char * const argv[],
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
rcl_arguments_t * args_output)
|
||||||
|
{
|
||||||
|
RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
|
||||||
|
if (argc < 0) {
|
||||||
|
return RCL_RET_INVALID_ARGUMENT;
|
||||||
|
} else if (argc > 0) {
|
||||||
|
RCL_CHECK_ARGUMENT_FOR_NULL(argv, RCL_RET_INVALID_ARGUMENT, allocator);
|
||||||
|
}
|
||||||
|
RCL_CHECK_ARGUMENT_FOR_NULL(args_output, RCL_RET_INVALID_ARGUMENT, allocator);
|
||||||
|
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_ret_t fail_ret;
|
||||||
|
|
||||||
|
args_output->impl = allocator.allocate(sizeof(rcl_arguments_impl_t), allocator.state);
|
||||||
|
if (NULL == args_output->impl) {
|
||||||
|
return RCL_RET_BAD_ALLOC;
|
||||||
|
}
|
||||||
|
rcl_arguments_impl_t * args_impl = args_output->impl;
|
||||||
|
args_impl->num_remap_rules = 0;
|
||||||
|
args_impl->remap_rules = NULL;
|
||||||
|
args_impl->unparsed_args = NULL;
|
||||||
|
args_impl->num_unparsed_args = 0;
|
||||||
|
args_impl->allocator = allocator;
|
||||||
|
|
||||||
|
if (argc == 0) {
|
||||||
|
// there are no arguments to parse
|
||||||
|
return RCL_RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// over-allocate arrays to match the number of arguments
|
||||||
|
args_impl->remap_rules = allocator.allocate(sizeof(rcl_remap_t) * argc, allocator.state);
|
||||||
|
if (NULL == args_impl->remap_rules) {
|
||||||
|
ret = RCL_RET_BAD_ALLOC;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
args_impl->unparsed_args = allocator.allocate(sizeof(int) * argc, allocator.state);
|
||||||
|
if (NULL == args_impl->unparsed_args) {
|
||||||
|
ret = RCL_RET_BAD_ALLOC;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to parse arguments as remap rules
|
||||||
|
for (int i = 0; i < argc; ++i) {
|
||||||
|
rcl_remap_t * rule = &(args_impl->remap_rules[args_impl->num_remap_rules]);
|
||||||
|
*rule = rcl_remap_get_zero_initialized();
|
||||||
|
if (RCL_RET_OK == _rcl_parse_remap_rule(argv[i], allocator, rule)) {
|
||||||
|
++(args_impl->num_remap_rules);
|
||||||
|
} else {
|
||||||
|
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "arg %d error '%s'", i, rcl_get_error_string());
|
||||||
|
rcl_reset_error();
|
||||||
|
args_impl->unparsed_args[args_impl->num_unparsed_args] = i;
|
||||||
|
++(args_impl->num_unparsed_args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shrink remap_rules array to match number of successfully parsed rules
|
||||||
|
if (args_impl->num_remap_rules > 0) {
|
||||||
|
args_impl->remap_rules = rcutils_reallocf(
|
||||||
|
args_impl->remap_rules, sizeof(rcl_remap_t) * args_impl->num_remap_rules, &allocator);
|
||||||
|
if (NULL == args_impl->remap_rules) {
|
||||||
|
ret = RCL_RET_BAD_ALLOC;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No remap rules
|
||||||
|
allocator.deallocate(args_impl->remap_rules, allocator.state);
|
||||||
|
args_impl->remap_rules = NULL;
|
||||||
|
}
|
||||||
|
// Shrink unparsed_args
|
||||||
|
if (0 == args_impl->num_unparsed_args) {
|
||||||
|
// No unparsed args
|
||||||
|
allocator.deallocate(args_impl->unparsed_args, allocator.state);
|
||||||
|
args_impl->unparsed_args = NULL;
|
||||||
|
} else if (args_impl->num_unparsed_args < argc) {
|
||||||
|
args_impl->unparsed_args = rcutils_reallocf(
|
||||||
|
args_impl->unparsed_args, sizeof(int) * args_impl->num_unparsed_args, &allocator);
|
||||||
|
if (NULL == args_impl->unparsed_args) {
|
||||||
|
ret = RCL_RET_BAD_ALLOC;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RCL_RET_OK;
|
||||||
|
fail:
|
||||||
|
fail_ret = ret;
|
||||||
|
if (NULL != args_impl) {
|
||||||
|
ret = rcl_arguments_fini(args_output);
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "Failed to fini arguments after earlier failure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fail_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rcl_arguments_get_count_unparsed(
|
||||||
|
rcl_arguments_t * args)
|
||||||
|
{
|
||||||
|
if (NULL == args || NULL == args->impl) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return args->impl->num_unparsed_args;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_arguments_get_unparsed(
|
||||||
|
rcl_arguments_t * args,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
int ** output_unparsed_indices)
|
||||||
|
{
|
||||||
|
RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
|
||||||
|
RCL_CHECK_ARGUMENT_FOR_NULL(args, RCL_RET_INVALID_ARGUMENT, allocator);
|
||||||
|
RCL_CHECK_ARGUMENT_FOR_NULL(args->impl, RCL_RET_INVALID_ARGUMENT, allocator);
|
||||||
|
RCL_CHECK_ARGUMENT_FOR_NULL(output_unparsed_indices, RCL_RET_INVALID_ARGUMENT, allocator);
|
||||||
|
|
||||||
|
*output_unparsed_indices = NULL;
|
||||||
|
if (args->impl->num_unparsed_args) {
|
||||||
|
*output_unparsed_indices = allocator.allocate(
|
||||||
|
sizeof(int) * args->impl->num_unparsed_args, allocator.state);
|
||||||
|
if (NULL == *output_unparsed_indices) {
|
||||||
|
return RCL_RET_BAD_ALLOC;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < args->impl->num_unparsed_args; ++i) {
|
||||||
|
(*output_unparsed_indices)[i] = args->impl->unparsed_args[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RCL_RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcl_arguments_t
|
||||||
|
rcl_get_zero_initialized_arguments(void)
|
||||||
|
{
|
||||||
|
static rcl_arguments_t default_arguments = {
|
||||||
|
.impl = NULL
|
||||||
|
};
|
||||||
|
return default_arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_arguments_fini(
|
||||||
|
rcl_arguments_t * args)
|
||||||
|
{
|
||||||
|
rcl_allocator_t alloc = rcl_get_default_allocator();
|
||||||
|
RCL_CHECK_ARGUMENT_FOR_NULL(args, RCL_RET_INVALID_ARGUMENT, alloc);
|
||||||
|
if (args->impl) {
|
||||||
|
rcl_ret_t ret = RCL_RET_OK;
|
||||||
|
alloc = args->impl->allocator;
|
||||||
|
if (args->impl->remap_rules) {
|
||||||
|
for (int i = 0; i < args->impl->num_remap_rules; ++i) {
|
||||||
|
rcl_ret_t remap_ret = rcl_remap_fini(&(args->impl->remap_rules[i]));
|
||||||
|
if (remap_ret != RCL_RET_OK) {
|
||||||
|
ret = remap_ret;
|
||||||
|
RCUTILS_LOG_ERROR_NAMED(
|
||||||
|
ROS_PACKAGE_NAME,
|
||||||
|
"Failed to finalize remap rule while finalizing arguments. Continuing...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args->impl->allocator.deallocate(args->impl->remap_rules, args->impl->allocator.state);
|
||||||
|
args->impl->remap_rules = NULL;
|
||||||
|
args->impl->num_remap_rules = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
args->impl->allocator.deallocate(args->impl->unparsed_args, args->impl->allocator.state);
|
||||||
|
args->impl->num_unparsed_args = 0;
|
||||||
|
args->impl->unparsed_args = NULL;
|
||||||
|
|
||||||
|
args->impl->allocator.deallocate(args->impl, args->impl->allocator.state);
|
||||||
|
args->impl = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
RCL_SET_ERROR_MSG("rcl_arguments_t finalized twice", alloc);
|
||||||
|
return RCL_RET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
RCL_PUBLIC
|
||||||
|
RCL_WARN_UNUSED
|
||||||
|
rcl_arguments_t *
|
||||||
|
rcl_get_global_arguments()
|
||||||
|
{
|
||||||
|
return &__rcl_global_arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
47
rcl/src/rcl/arguments_impl.h
Normal file
47
rcl/src/rcl/arguments_impl.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2018 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCL__ARGUMENTS_IMPL_H_
|
||||||
|
#define RCL__ARGUMENTS_IMPL_H_
|
||||||
|
|
||||||
|
#include "rcl/arguments.h"
|
||||||
|
#include "./remap_impl.h"
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// \internal
|
||||||
|
typedef struct rcl_arguments_impl_t
|
||||||
|
{
|
||||||
|
/// Array of indices that were not valid ROS arguments.
|
||||||
|
int * unparsed_args;
|
||||||
|
/// Length of unparsed_args.
|
||||||
|
int num_unparsed_args;
|
||||||
|
|
||||||
|
/// Array of rules for name remapping.
|
||||||
|
rcl_remap_t * remap_rules;
|
||||||
|
/// Length of remap_rules.
|
||||||
|
int num_remap_rules;
|
||||||
|
|
||||||
|
/// Allocator used to allocate objects in this struct
|
||||||
|
rcl_allocator_t allocator;
|
||||||
|
} rcl_arguments_impl_t;
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RCL__ARGUMENTS_IMPL_H_
|
|
@ -24,6 +24,7 @@ extern "C"
|
||||||
|
|
||||||
#include "rcl/error_handling.h"
|
#include "rcl/error_handling.h"
|
||||||
#include "rcl/expand_topic_name.h"
|
#include "rcl/expand_topic_name.h"
|
||||||
|
#include "rcl/remap.h"
|
||||||
#include "rcutils/logging_macros.h"
|
#include "rcutils/logging_macros.h"
|
||||||
#include "rmw/error_handling.h"
|
#include "rmw/error_handling.h"
|
||||||
#include "rmw/rmw.h"
|
#include "rmw/rmw.h"
|
||||||
|
@ -100,6 +101,7 @@ rcl_client_init(
|
||||||
return RCL_RET_ERROR;
|
return RCL_RET_ERROR;
|
||||||
}
|
}
|
||||||
char * expanded_service_name = NULL;
|
char * expanded_service_name = NULL;
|
||||||
|
char * remapped_service_name = NULL;
|
||||||
ret = rcl_expand_topic_name(
|
ret = rcl_expand_topic_name(
|
||||||
service_name,
|
service_name,
|
||||||
rcl_node_get_name(node),
|
rcl_node_get_name(node),
|
||||||
|
@ -114,40 +116,60 @@ rcl_client_init(
|
||||||
return RCL_RET_ERROR;
|
return RCL_RET_ERROR;
|
||||||
}
|
}
|
||||||
if (ret != RCL_RET_OK) {
|
if (ret != RCL_RET_OK) {
|
||||||
if (ret == RCL_RET_BAD_ALLOC) {
|
if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
|
||||||
return ret;
|
ret = RCL_RET_SERVICE_NAME_INVALID;
|
||||||
} else if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
|
|
||||||
return RCL_RET_SERVICE_NAME_INVALID;
|
|
||||||
} else {
|
} else {
|
||||||
return RCL_RET_ERROR;
|
ret = RCL_RET_ERROR;
|
||||||
}
|
}
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Expanded service name '%s'", expanded_service_name)
|
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Expanded service name '%s'", expanded_service_name)
|
||||||
|
|
||||||
|
const rcl_node_options_t * node_options = rcl_node_get_options(node);
|
||||||
|
if (NULL == node_options) {
|
||||||
|
ret = RCL_RET_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
rcl_arguments_t * global_args = NULL;
|
||||||
|
if (node_options->use_global_arguments) {
|
||||||
|
global_args = rcl_get_global_arguments();
|
||||||
|
}
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
&(node_options->arguments), global_args, expanded_service_name,
|
||||||
|
rcl_node_get_name(node), rcl_node_get_namespace(node), *allocator, &remapped_service_name);
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
goto fail;
|
||||||
|
} else if (NULL == remapped_service_name) {
|
||||||
|
remapped_service_name = expanded_service_name;
|
||||||
|
expanded_service_name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the expanded service name.
|
// Validate the expanded service name.
|
||||||
int validation_result;
|
int validation_result;
|
||||||
rmw_ret_t rmw_ret = rmw_validate_full_topic_name(expanded_service_name, &validation_result, NULL);
|
rmw_ret_t rmw_ret = rmw_validate_full_topic_name(remapped_service_name, &validation_result, NULL);
|
||||||
if (rmw_ret != RMW_RET_OK) {
|
if (rmw_ret != RMW_RET_OK) {
|
||||||
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
||||||
return RCL_RET_ERROR;
|
ret = RCL_RET_ERROR;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (validation_result != RMW_TOPIC_VALID) {
|
if (validation_result != RMW_TOPIC_VALID) {
|
||||||
RCL_SET_ERROR_MSG(rmw_full_topic_name_validation_result_string(validation_result), *allocator)
|
RCL_SET_ERROR_MSG(rmw_full_topic_name_validation_result_string(validation_result), *allocator)
|
||||||
return RCL_RET_SERVICE_NAME_INVALID;
|
ret = RCL_RET_SERVICE_NAME_INVALID;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
// Allocate space for the implementation struct.
|
// Allocate space for the implementation struct.
|
||||||
client->impl = (rcl_client_impl_t *)allocator->allocate(
|
client->impl = (rcl_client_impl_t *)allocator->allocate(
|
||||||
sizeof(rcl_client_impl_t), allocator->state);
|
sizeof(rcl_client_impl_t), allocator->state);
|
||||||
RCL_CHECK_FOR_NULL_WITH_MSG(
|
RCL_CHECK_FOR_NULL_WITH_MSG(
|
||||||
client->impl, "allocating memory failed", return RCL_RET_BAD_ALLOC, *allocator);
|
client->impl, "allocating memory failed", ret = RCL_RET_BAD_ALLOC; goto cleanup, *allocator);
|
||||||
// Fill out implementation struct.
|
// Fill out implementation struct.
|
||||||
// rmw handle (create rmw client)
|
// rmw handle (create rmw client)
|
||||||
// TODO(wjwwood): pass along the allocator to rmw when it supports it
|
// TODO(wjwwood): pass along the allocator to rmw when it supports it
|
||||||
client->impl->rmw_handle = rmw_create_client(
|
client->impl->rmw_handle = rmw_create_client(
|
||||||
rcl_node_get_rmw_handle(node),
|
rcl_node_get_rmw_handle(node),
|
||||||
type_support,
|
type_support,
|
||||||
expanded_service_name,
|
remapped_service_name,
|
||||||
&options->qos);
|
&options->qos);
|
||||||
allocator->deallocate(expanded_service_name, allocator->state);
|
|
||||||
if (!client->impl->rmw_handle) {
|
if (!client->impl->rmw_handle) {
|
||||||
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -155,12 +177,22 @@ rcl_client_init(
|
||||||
// options
|
// options
|
||||||
client->impl->options = *options;
|
client->impl->options = *options;
|
||||||
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Client initialized")
|
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Client initialized")
|
||||||
return RCL_RET_OK;
|
ret = RCL_RET_OK;
|
||||||
|
goto cleanup;
|
||||||
fail:
|
fail:
|
||||||
if (client->impl) {
|
if (client->impl) {
|
||||||
allocator->deallocate(client->impl, allocator->state);
|
allocator->deallocate(client->impl, allocator->state);
|
||||||
}
|
}
|
||||||
return fail_ret;
|
ret = fail_ret;
|
||||||
|
// Fall through to cleanup
|
||||||
|
cleanup:
|
||||||
|
if (NULL != expanded_service_name) {
|
||||||
|
allocator->deallocate(expanded_service_name, allocator->state);
|
||||||
|
}
|
||||||
|
if (NULL != remapped_service_name) {
|
||||||
|
allocator->deallocate(remapped_service_name, allocator->state);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcl_ret_t
|
rcl_ret_t
|
||||||
|
|
|
@ -24,8 +24,10 @@ extern "C"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "rcl/arguments.h"
|
||||||
#include "rcl/error_handling.h"
|
#include "rcl/error_handling.h"
|
||||||
#include "rcl/rcl.h"
|
#include "rcl/rcl.h"
|
||||||
|
#include "rcl/remap.h"
|
||||||
#include "rcutils/filesystem.h"
|
#include "rcutils/filesystem.h"
|
||||||
#include "rcutils/find.h"
|
#include "rcutils/find.h"
|
||||||
#include "rcutils/format_string.h"
|
#include "rcutils/format_string.h"
|
||||||
|
@ -142,6 +144,7 @@ rcl_node_init(
|
||||||
rcl_guard_condition_get_default_options();
|
rcl_guard_condition_get_default_options();
|
||||||
rcl_ret_t ret;
|
rcl_ret_t ret;
|
||||||
rcl_ret_t fail_ret = RCL_RET_ERROR;
|
rcl_ret_t fail_ret = RCL_RET_ERROR;
|
||||||
|
char * remapped_node_name = NULL;
|
||||||
|
|
||||||
// Check options and allocator first, so allocator can be used for errors.
|
// Check options and allocator first, so allocator can be used for errors.
|
||||||
RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT, rcl_get_default_allocator());
|
RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT, rcl_get_default_allocator());
|
||||||
|
@ -191,7 +194,7 @@ rcl_node_init(
|
||||||
// length + 2, because new leading / and terminating \0
|
// length + 2, because new leading / and terminating \0
|
||||||
char * temp = (char *)allocator->allocate(namespace_length + 2, allocator->state);
|
char * temp = (char *)allocator->allocate(namespace_length + 2, allocator->state);
|
||||||
RCL_CHECK_FOR_NULL_WITH_MSG(
|
RCL_CHECK_FOR_NULL_WITH_MSG(
|
||||||
temp, "allocating memory failed", return RCL_RET_BAD_ALLOC, *allocator);
|
temp, "allocating memory failed", ret = RCL_RET_BAD_ALLOC; goto cleanup, *allocator);
|
||||||
temp[0] = '/';
|
temp[0] = '/';
|
||||||
memcpy(temp + 1, namespace_, strlen(namespace_) + 1);
|
memcpy(temp + 1, namespace_, strlen(namespace_) + 1);
|
||||||
local_namespace_ = temp;
|
local_namespace_ = temp;
|
||||||
|
@ -202,34 +205,54 @@ rcl_node_init(
|
||||||
ret = rmw_validate_namespace(local_namespace_, &validation_result, NULL);
|
ret = rmw_validate_namespace(local_namespace_, &validation_result, NULL);
|
||||||
if (ret != RMW_RET_OK) {
|
if (ret != RMW_RET_OK) {
|
||||||
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
||||||
if (should_free_local_namespace_) {
|
goto cleanup;
|
||||||
allocator->deallocate((char *)local_namespace_, allocator->state);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
if (validation_result != RMW_NAMESPACE_VALID) {
|
if (validation_result != RMW_NAMESPACE_VALID) {
|
||||||
const char * msg = rmw_namespace_validation_result_string(validation_result);
|
const char * msg = rmw_namespace_validation_result_string(validation_result);
|
||||||
RCL_SET_ERROR_MSG_WITH_FORMAT_STRING((*allocator), "%s, result: %d", msg, validation_result);
|
RCL_SET_ERROR_MSG_WITH_FORMAT_STRING((*allocator), "%s, result: %d", msg, validation_result);
|
||||||
|
|
||||||
if (should_free_local_namespace_) {
|
ret = RCL_RET_NODE_INVALID_NAMESPACE;
|
||||||
allocator->deallocate((char *)local_namespace_, allocator->state);
|
goto cleanup;
|
||||||
}
|
|
||||||
return RCL_RET_NODE_INVALID_NAMESPACE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate space for the implementation struct.
|
// Allocate space for the implementation struct.
|
||||||
node->impl = (rcl_node_impl_t *)allocator->allocate(sizeof(rcl_node_impl_t), allocator->state);
|
node->impl = (rcl_node_impl_t *)allocator->allocate(sizeof(rcl_node_impl_t), allocator->state);
|
||||||
if (!node->impl && should_free_local_namespace_) {
|
|
||||||
allocator->deallocate((char *)local_namespace_, allocator->state);
|
|
||||||
}
|
|
||||||
RCL_CHECK_FOR_NULL_WITH_MSG(
|
RCL_CHECK_FOR_NULL_WITH_MSG(
|
||||||
node->impl, "allocating memory failed", return RCL_RET_BAD_ALLOC, *allocator);
|
node->impl, "allocating memory failed", ret = RCL_RET_BAD_ALLOC; goto cleanup, *allocator);
|
||||||
node->impl->rmw_node_handle = NULL;
|
node->impl->rmw_node_handle = NULL;
|
||||||
node->impl->graph_guard_condition = NULL;
|
node->impl->graph_guard_condition = NULL;
|
||||||
|
node->impl->logger_name = NULL;
|
||||||
// Initialize node impl.
|
// Initialize node impl.
|
||||||
// node options (assume it is trivially copyable)
|
// node options (assume it is trivially copyable)
|
||||||
node->impl->options = *options;
|
node->impl->options = *options;
|
||||||
|
|
||||||
|
// Remap the node name and namespace if remap rules are given
|
||||||
|
rcl_arguments_t * global_args = NULL;
|
||||||
|
if (node->impl->options.use_global_arguments) {
|
||||||
|
global_args = rcl_get_global_arguments();
|
||||||
|
}
|
||||||
|
ret = rcl_remap_node_name(
|
||||||
|
&(node->impl->options.arguments), global_args, name, *allocator,
|
||||||
|
&remapped_node_name);
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
goto fail;
|
||||||
|
} else if (NULL != remapped_node_name) {
|
||||||
|
name = remapped_node_name;
|
||||||
|
}
|
||||||
|
char * remapped_namespace = NULL;
|
||||||
|
ret = rcl_remap_node_namespace(
|
||||||
|
&(node->impl->options.arguments), global_args, local_namespace_,
|
||||||
|
*allocator, &remapped_namespace);
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
goto fail;
|
||||||
|
} else if (NULL != remapped_namespace) {
|
||||||
|
if (should_free_local_namespace_) {
|
||||||
|
allocator->deallocate((char *)local_namespace_, allocator->state);
|
||||||
|
}
|
||||||
|
should_free_local_namespace_ = true;
|
||||||
|
local_namespace_ = remapped_namespace;
|
||||||
|
}
|
||||||
|
|
||||||
// node logger name
|
// node logger name
|
||||||
node->impl->logger_name = rcl_create_node_logger_name(name, local_namespace_, allocator);
|
node->impl->logger_name = rcl_create_node_logger_name(name, local_namespace_, allocator);
|
||||||
RCL_CHECK_FOR_NULL_WITH_MSG(
|
RCL_CHECK_FOR_NULL_WITH_MSG(
|
||||||
|
@ -264,10 +287,8 @@ rcl_node_init(
|
||||||
RCL_SET_ERROR_MSG(
|
RCL_SET_ERROR_MSG(
|
||||||
"Environment variable " RCUTILS_STRINGIFY(ROS_SECURITY_ENABLE_VAR_NAME)
|
"Environment variable " RCUTILS_STRINGIFY(ROS_SECURITY_ENABLE_VAR_NAME)
|
||||||
" could not be read", rcl_get_default_allocator());
|
" could not be read", rcl_get_default_allocator());
|
||||||
if (should_free_local_namespace_) {
|
ret = RCL_RET_ERROR;
|
||||||
allocator->deallocate((char *)local_namespace_, allocator->state);
|
goto fail;
|
||||||
}
|
|
||||||
return RCL_RET_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool use_security = (0 == strcmp(ros_security_enable, "true"));
|
bool use_security = (0 == strcmp(ros_security_enable, "true"));
|
||||||
|
@ -278,10 +299,8 @@ rcl_node_init(
|
||||||
RCL_SET_ERROR_MSG(
|
RCL_SET_ERROR_MSG(
|
||||||
"Environment variable " RCUTILS_STRINGIFY(ROS_SECURITY_STRATEGY_VAR_NAME)
|
"Environment variable " RCUTILS_STRINGIFY(ROS_SECURITY_STRATEGY_VAR_NAME)
|
||||||
" could not be read", rcl_get_default_allocator());
|
" could not be read", rcl_get_default_allocator());
|
||||||
if (should_free_local_namespace_) {
|
ret = RCL_RET_ERROR;
|
||||||
allocator->deallocate((char *)local_namespace_, allocator->state);
|
goto fail;
|
||||||
}
|
|
||||||
return RCL_RET_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rmw_node_security_options_t node_security_options =
|
rmw_node_security_options_t node_security_options =
|
||||||
|
@ -302,10 +321,8 @@ rcl_node_init(
|
||||||
"SECURITY ERROR: unable to find a folder matching the node name in the "
|
"SECURITY ERROR: unable to find a folder matching the node name in the "
|
||||||
RCUTILS_STRINGIFY(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME)
|
RCUTILS_STRINGIFY(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME)
|
||||||
" directory while the requested security strategy requires it", *allocator);
|
" directory while the requested security strategy requires it", *allocator);
|
||||||
if (should_free_local_namespace_) {
|
ret = RCL_RET_ERROR;
|
||||||
allocator->deallocate((char *)local_namespace_, allocator->state);
|
goto cleanup;
|
||||||
}
|
|
||||||
return RCL_RET_ERROR;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,11 +331,6 @@ rcl_node_init(
|
||||||
|
|
||||||
RCL_CHECK_FOR_NULL_WITH_MSG(
|
RCL_CHECK_FOR_NULL_WITH_MSG(
|
||||||
node->impl->rmw_node_handle, rmw_get_error_string_safe(), goto fail, *allocator);
|
node->impl->rmw_node_handle, rmw_get_error_string_safe(), goto fail, *allocator);
|
||||||
// free local_namespace_ if necessary
|
|
||||||
if (should_free_local_namespace_) {
|
|
||||||
allocator->deallocate((char *)local_namespace_, allocator->state);
|
|
||||||
should_free_local_namespace_ = false;
|
|
||||||
}
|
|
||||||
// instance id
|
// instance id
|
||||||
node->impl->rcl_instance_id = rcl_get_instance_id();
|
node->impl->rcl_instance_id = rcl_get_instance_id();
|
||||||
// graph guard condition
|
// graph guard condition
|
||||||
|
@ -345,7 +357,8 @@ rcl_node_init(
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Node initialized")
|
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Node initialized")
|
||||||
return RCL_RET_OK;
|
ret = RCL_RET_OK;
|
||||||
|
goto cleanup;
|
||||||
fail:
|
fail:
|
||||||
if (node->impl) {
|
if (node->impl) {
|
||||||
if (node->impl->logger_name) {
|
if (node->impl->logger_name) {
|
||||||
|
@ -374,11 +387,17 @@ fail:
|
||||||
}
|
}
|
||||||
*node = rcl_get_zero_initialized_node();
|
*node = rcl_get_zero_initialized_node();
|
||||||
|
|
||||||
|
ret = fail_ret;
|
||||||
|
// fall through from fail -> cleanup
|
||||||
|
cleanup:
|
||||||
if (should_free_local_namespace_) {
|
if (should_free_local_namespace_) {
|
||||||
allocator->deallocate((char *)local_namespace_, allocator->state);
|
allocator->deallocate((char *)local_namespace_, allocator->state);
|
||||||
local_namespace_ = NULL;
|
local_namespace_ = NULL;
|
||||||
}
|
}
|
||||||
return fail_ret;
|
if (NULL != remapped_node_name) {
|
||||||
|
allocator->deallocate(remapped_node_name, allocator->state);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcl_ret_t
|
rcl_ret_t
|
||||||
|
@ -435,9 +454,11 @@ rcl_node_get_default_options()
|
||||||
// !!! MAKE SURE THAT CHANGES TO THESE DEFAULTS ARE REFLECTED IN THE HEADER DOC STRING
|
// !!! MAKE SURE THAT CHANGES TO THESE DEFAULTS ARE REFLECTED IN THE HEADER DOC STRING
|
||||||
static rcl_node_options_t default_options = {
|
static rcl_node_options_t default_options = {
|
||||||
.domain_id = RCL_NODE_OPTIONS_DEFAULT_DOMAIN_ID,
|
.domain_id = RCL_NODE_OPTIONS_DEFAULT_DOMAIN_ID,
|
||||||
|
.use_global_arguments = true,
|
||||||
};
|
};
|
||||||
// Must set the allocator after because it is not a compile time constant.
|
// Must set the allocator after because it is not a compile time constant.
|
||||||
default_options.allocator = rcl_get_default_allocator();
|
default_options.allocator = rcl_get_default_allocator();
|
||||||
|
default_options.arguments = rcl_get_zero_initialized_arguments();
|
||||||
return default_options;
|
return default_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ extern "C"
|
||||||
#include "rcl/allocator.h"
|
#include "rcl/allocator.h"
|
||||||
#include "rcl/error_handling.h"
|
#include "rcl/error_handling.h"
|
||||||
#include "rcl/expand_topic_name.h"
|
#include "rcl/expand_topic_name.h"
|
||||||
|
#include "rcl/remap.h"
|
||||||
#include "rcutils/logging_macros.h"
|
#include "rcutils/logging_macros.h"
|
||||||
#include "rmw/error_handling.h"
|
#include "rmw/error_handling.h"
|
||||||
#include "rmw/rmw.h"
|
#include "rmw/rmw.h"
|
||||||
|
@ -99,6 +100,7 @@ rcl_publisher_init(
|
||||||
return RCL_RET_ERROR;
|
return RCL_RET_ERROR;
|
||||||
}
|
}
|
||||||
char * expanded_topic_name = NULL;
|
char * expanded_topic_name = NULL;
|
||||||
|
char * remapped_topic_name = NULL;
|
||||||
ret = rcl_expand_topic_name(
|
ret = rcl_expand_topic_name(
|
||||||
topic_name,
|
topic_name,
|
||||||
rcl_node_get_name(node),
|
rcl_node_get_name(node),
|
||||||
|
@ -108,56 +110,85 @@ rcl_publisher_init(
|
||||||
&expanded_topic_name);
|
&expanded_topic_name);
|
||||||
rcutils_ret = rcutils_string_map_fini(&substitutions_map);
|
rcutils_ret = rcutils_string_map_fini(&substitutions_map);
|
||||||
if (rcutils_ret != RCUTILS_RET_OK) {
|
if (rcutils_ret != RCUTILS_RET_OK) {
|
||||||
RCL_SET_ERROR_MSG(rcutils_get_error_string_safe(), *allocator)
|
RCL_SET_ERROR_MSG(rcutils_get_error_string_safe(), *allocator);
|
||||||
allocator->deallocate(expanded_topic_name, allocator->state);
|
ret = RCL_RET_ERROR;
|
||||||
return RCL_RET_ERROR;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (ret != RCL_RET_OK) {
|
if (ret != RCL_RET_OK) {
|
||||||
if (ret == RCL_RET_BAD_ALLOC) {
|
if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
|
||||||
return ret;
|
ret = RCL_RET_TOPIC_NAME_INVALID;
|
||||||
} else if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
|
|
||||||
return RCL_RET_TOPIC_NAME_INVALID;
|
|
||||||
} else {
|
} else {
|
||||||
return RCL_RET_ERROR;
|
ret = RCL_RET_ERROR;
|
||||||
}
|
}
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Expanded topic name '%s'", expanded_topic_name)
|
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Expanded topic name '%s'", expanded_topic_name)
|
||||||
|
|
||||||
|
const rcl_node_options_t * node_options = rcl_node_get_options(node);
|
||||||
|
if (NULL == node_options) {
|
||||||
|
ret = RCL_RET_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
rcl_arguments_t * global_args = NULL;
|
||||||
|
if (node_options->use_global_arguments) {
|
||||||
|
global_args = rcl_get_global_arguments();
|
||||||
|
}
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
&(node_options->arguments), global_args, expanded_topic_name,
|
||||||
|
rcl_node_get_name(node), rcl_node_get_namespace(node), *allocator, &remapped_topic_name);
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
goto fail;
|
||||||
|
} else if (NULL == remapped_topic_name) {
|
||||||
|
remapped_topic_name = expanded_topic_name;
|
||||||
|
expanded_topic_name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the expanded topic name.
|
// Validate the expanded topic name.
|
||||||
int validation_result;
|
int validation_result;
|
||||||
rmw_ret_t rmw_ret = rmw_validate_full_topic_name(expanded_topic_name, &validation_result, NULL);
|
rmw_ret_t rmw_ret = rmw_validate_full_topic_name(remapped_topic_name, &validation_result, NULL);
|
||||||
if (rmw_ret != RMW_RET_OK) {
|
if (rmw_ret != RMW_RET_OK) {
|
||||||
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
||||||
return RCL_RET_ERROR;
|
ret = RCL_RET_ERROR;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (validation_result != RMW_TOPIC_VALID) {
|
if (validation_result != RMW_TOPIC_VALID) {
|
||||||
RCL_SET_ERROR_MSG(rmw_full_topic_name_validation_result_string(validation_result), *allocator)
|
RCL_SET_ERROR_MSG(rmw_full_topic_name_validation_result_string(validation_result), *allocator)
|
||||||
return RCL_RET_TOPIC_NAME_INVALID;
|
ret = RCL_RET_TOPIC_NAME_INVALID;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
// Allocate space for the implementation struct.
|
// Allocate space for the implementation struct.
|
||||||
publisher->impl = (rcl_publisher_impl_t *)allocator->allocate(
|
publisher->impl = (rcl_publisher_impl_t *)allocator->allocate(
|
||||||
sizeof(rcl_publisher_impl_t), allocator->state);
|
sizeof(rcl_publisher_impl_t), allocator->state);
|
||||||
RCL_CHECK_FOR_NULL_WITH_MSG(
|
RCL_CHECK_FOR_NULL_WITH_MSG(
|
||||||
publisher->impl, "allocating memory failed", return RCL_RET_BAD_ALLOC, *allocator);
|
publisher->impl, "allocating memory failed", ret = RCL_RET_BAD_ALLOC; goto cleanup, *allocator);
|
||||||
// Fill out implementation struct.
|
// Fill out implementation struct.
|
||||||
// rmw handle (create rmw publisher)
|
// rmw handle (create rmw publisher)
|
||||||
// TODO(wjwwood): pass along the allocator to rmw when it supports it
|
// TODO(wjwwood): pass along the allocator to rmw when it supports it
|
||||||
publisher->impl->rmw_handle = rmw_create_publisher(
|
publisher->impl->rmw_handle = rmw_create_publisher(
|
||||||
rcl_node_get_rmw_handle(node),
|
rcl_node_get_rmw_handle(node),
|
||||||
type_support,
|
type_support,
|
||||||
expanded_topic_name,
|
remapped_topic_name,
|
||||||
&(options->qos));
|
&(options->qos));
|
||||||
allocator->deallocate(expanded_topic_name, allocator->state);
|
|
||||||
RCL_CHECK_FOR_NULL_WITH_MSG(publisher->impl->rmw_handle,
|
RCL_CHECK_FOR_NULL_WITH_MSG(publisher->impl->rmw_handle,
|
||||||
rmw_get_error_string_safe(), goto fail, *allocator);
|
rmw_get_error_string_safe(), goto fail, *allocator);
|
||||||
// options
|
// options
|
||||||
publisher->impl->options = *options;
|
publisher->impl->options = *options;
|
||||||
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Publisher initialized")
|
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Publisher initialized");
|
||||||
return RCL_RET_OK;
|
goto cleanup;
|
||||||
fail:
|
fail:
|
||||||
if (publisher->impl) {
|
if (publisher->impl) {
|
||||||
allocator->deallocate(publisher->impl, allocator->state);
|
allocator->deallocate(publisher->impl, allocator->state);
|
||||||
}
|
}
|
||||||
return fail_ret;
|
ret = fail_ret;
|
||||||
|
// Fall through to cleanup
|
||||||
|
cleanup:
|
||||||
|
if (NULL != expanded_topic_name) {
|
||||||
|
allocator->deallocate(expanded_topic_name, allocator->state);
|
||||||
|
}
|
||||||
|
if (NULL != remapped_topic_name) {
|
||||||
|
allocator->deallocate(remapped_topic_name, allocator->state);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcl_ret_t
|
rcl_ret_t
|
||||||
|
|
|
@ -21,7 +21,9 @@ extern "C"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "./arguments_impl.h"
|
||||||
#include "./stdatomic_helper.h"
|
#include "./stdatomic_helper.h"
|
||||||
|
#include "rcl/arguments.h"
|
||||||
#include "rcl/error_handling.h"
|
#include "rcl/error_handling.h"
|
||||||
#include "rcutils/logging_macros.h"
|
#include "rcutils/logging_macros.h"
|
||||||
#include "rmw/error_handling.h"
|
#include "rmw/error_handling.h"
|
||||||
|
@ -49,6 +51,11 @@ __clean_up_init()
|
||||||
}
|
}
|
||||||
__rcl_argc = 0;
|
__rcl_argc = 0;
|
||||||
__rcl_argv = NULL;
|
__rcl_argv = NULL;
|
||||||
|
// This is the only place where it is OK to finalize the global arguments.
|
||||||
|
rcl_arguments_t * global_args = rcl_get_global_arguments();
|
||||||
|
if (NULL != global_args->impl && RCL_RET_OK != rcl_arguments_fini(global_args)) {
|
||||||
|
rcl_reset_error();
|
||||||
|
}
|
||||||
rcl_atomic_store(&__rcl_instance_id, 0);
|
rcl_atomic_store(&__rcl_instance_id, 0);
|
||||||
rcl_atomic_store(&__rcl_is_initialized, false);
|
rcl_atomic_store(&__rcl_is_initialized, false);
|
||||||
}
|
}
|
||||||
|
@ -68,6 +75,11 @@ rcl_init(int argc, char ** argv, rcl_allocator_t allocator)
|
||||||
RCL_SET_ERROR_MSG("rcl_init called while already initialized", allocator);
|
RCL_SET_ERROR_MSG("rcl_init called while already initialized", allocator);
|
||||||
return RCL_RET_ALREADY_INIT;
|
return RCL_RET_ALREADY_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Zero initialize global arguments before any chance of calling __clean_up_init()
|
||||||
|
rcl_arguments_t * global_args = rcl_get_global_arguments();
|
||||||
|
*global_args = rcl_get_zero_initialized_arguments();
|
||||||
|
|
||||||
// There is a race condition between the time __rcl_is_initialized is set true,
|
// There is a race condition between the time __rcl_is_initialized is set true,
|
||||||
// and when the allocator is set, in which rcl_shutdown() could get rcl_ok() as
|
// and when the allocator is set, in which rcl_shutdown() could get rcl_ok() as
|
||||||
// true and try to use the allocator, but it isn't set yet...
|
// true and try to use the allocator, but it isn't set yet...
|
||||||
|
@ -101,6 +113,10 @@ rcl_init(int argc, char ** argv, rcl_allocator_t allocator)
|
||||||
}
|
}
|
||||||
memcpy(__rcl_argv[i], argv[i], strlen(argv[i]));
|
memcpy(__rcl_argv[i], argv[i], strlen(argv[i]));
|
||||||
}
|
}
|
||||||
|
if (RCL_RET_OK != rcl_parse_arguments(argc, (const char **)argv, allocator, global_args)) {
|
||||||
|
RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "Failed to parse global arguments");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
rcl_atomic_store(&__rcl_instance_id, ++__rcl_next_unique_id);
|
rcl_atomic_store(&__rcl_instance_id, ++__rcl_next_unique_id);
|
||||||
if (rcl_atomic_load_uint64_t(&__rcl_instance_id) == 0) {
|
if (rcl_atomic_load_uint64_t(&__rcl_instance_id) == 0) {
|
||||||
// Roll over occurred.
|
// Roll over occurred.
|
||||||
|
|
279
rcl/src/rcl/remap.c
Normal file
279
rcl/src/rcl/remap.c
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
// Copyright 2018 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "rcl/remap.h"
|
||||||
|
|
||||||
|
#include "./arguments_impl.h"
|
||||||
|
#include "./remap_impl.h"
|
||||||
|
#include "rcl/error_handling.h"
|
||||||
|
#include "rcl/expand_topic_name.h"
|
||||||
|
#include "rcutils/allocator.h"
|
||||||
|
#include "rcutils/strdup.h"
|
||||||
|
#include "rcutils/types/string_map.h"
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rcl_remap_t
|
||||||
|
rcl_remap_get_zero_initialized()
|
||||||
|
{
|
||||||
|
rcl_remap_t rule;
|
||||||
|
rule.type = RCL_UNKNOWN_REMAP;
|
||||||
|
rule.node_name = NULL;
|
||||||
|
rule.match = NULL;
|
||||||
|
rule.replacement = NULL;
|
||||||
|
rule.allocator = rcutils_get_zero_initialized_allocator();
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_remap_fini(
|
||||||
|
rcl_remap_t * rule)
|
||||||
|
{
|
||||||
|
if (NULL != rule->node_name) {
|
||||||
|
rule->allocator.deallocate(rule->node_name, rule->allocator.state);
|
||||||
|
rule->node_name = NULL;
|
||||||
|
}
|
||||||
|
if (NULL != rule->match) {
|
||||||
|
rule->allocator.deallocate(rule->match, rule->allocator.state);
|
||||||
|
rule->match = NULL;
|
||||||
|
}
|
||||||
|
if (NULL != rule->replacement) {
|
||||||
|
rule->allocator.deallocate(rule->replacement, rule->allocator.state);
|
||||||
|
rule->replacement = NULL;
|
||||||
|
}
|
||||||
|
rule->allocator = rcutils_get_zero_initialized_allocator();
|
||||||
|
return RCL_RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the first matching rule in a chain.
|
||||||
|
/// \return RCL_RET_OK if no errors occurred while searching for a rule
|
||||||
|
RCL_LOCAL
|
||||||
|
rcl_ret_t
|
||||||
|
_rcl_remap_first_match(
|
||||||
|
rcl_remap_t * remap_rules,
|
||||||
|
int num_rules,
|
||||||
|
rcl_remap_type_t type_bitmask,
|
||||||
|
const char * name,
|
||||||
|
const char * node_name,
|
||||||
|
const char * node_namespace,
|
||||||
|
const rcutils_string_map_t * substitutions,
|
||||||
|
rcutils_allocator_t allocator,
|
||||||
|
rcl_remap_t ** output_rule)
|
||||||
|
{
|
||||||
|
*output_rule = NULL;
|
||||||
|
for (int i = 0; i < num_rules; ++i) {
|
||||||
|
rcl_remap_t * rule = &(remap_rules[i]);
|
||||||
|
if (!(rule->type & type_bitmask)) {
|
||||||
|
// Not the type of remap rule we're looking fore
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (rule->node_name != NULL && 0 != strcmp(rule->node_name, node_name)) {
|
||||||
|
// Rule has a node name prefix and the supplied node name didn't match
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool matched = false;
|
||||||
|
if (rule->type & (RCL_TOPIC_REMAP | RCL_SERVICE_REMAP)) {
|
||||||
|
// topic and service rules need the match side to be expanded to a FQN
|
||||||
|
char * expanded_match = NULL;
|
||||||
|
rcl_ret_t ret = rcl_expand_topic_name(
|
||||||
|
rule->match, node_name, node_namespace, substitutions, allocator, &expanded_match);
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
rcl_reset_error();
|
||||||
|
if (
|
||||||
|
RCL_RET_NODE_INVALID_NAMESPACE == ret ||
|
||||||
|
RCL_RET_NODE_INVALID_NAME == ret ||
|
||||||
|
RCL_RET_BAD_ALLOC == ret)
|
||||||
|
{
|
||||||
|
// these are probably going to happen again. Stop processing rules
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
matched = (0 == strcmp(expanded_match, name));
|
||||||
|
allocator.deallocate(expanded_match, allocator.state);
|
||||||
|
} else {
|
||||||
|
// nodename and namespace replacement apply if the type and node name prefix checks passed
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
if (matched) {
|
||||||
|
*output_rule = rule;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RCL_RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remap from one name to another using rules matching a given type bitmask.
|
||||||
|
RCL_LOCAL
|
||||||
|
rcl_ret_t
|
||||||
|
_rcl_remap_name(
|
||||||
|
const rcl_arguments_t * local_arguments,
|
||||||
|
const rcl_arguments_t * global_arguments,
|
||||||
|
rcl_remap_type_t type_bitmask,
|
||||||
|
const char * name,
|
||||||
|
const char * node_name,
|
||||||
|
const char * node_namespace,
|
||||||
|
const rcutils_string_map_t * substitutions,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
char ** output_name)
|
||||||
|
{
|
||||||
|
RCL_CHECK_ARGUMENT_FOR_NULL(node_name, RCL_RET_INVALID_ARGUMENT, allocator);
|
||||||
|
RCL_CHECK_ARGUMENT_FOR_NULL(output_name, RCL_RET_INVALID_ARGUMENT, allocator);
|
||||||
|
if (NULL != local_arguments && NULL == local_arguments->impl) {
|
||||||
|
local_arguments = NULL;
|
||||||
|
}
|
||||||
|
if (NULL != global_arguments && NULL == global_arguments->impl) {
|
||||||
|
global_arguments = NULL;
|
||||||
|
}
|
||||||
|
if (NULL == local_arguments && NULL == global_arguments) {
|
||||||
|
RCL_SET_ERROR_MSG("local_arguments invalid and not using global arguments", allocator);
|
||||||
|
return RCL_RET_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*output_name = NULL;
|
||||||
|
rcl_remap_t * rule = NULL;
|
||||||
|
|
||||||
|
// Look at local rules first
|
||||||
|
if (NULL != local_arguments) {
|
||||||
|
rcl_ret_t ret = _rcl_remap_first_match(
|
||||||
|
local_arguments->impl->remap_rules, local_arguments->impl->num_remap_rules, type_bitmask,
|
||||||
|
name, node_name, node_namespace, substitutions, allocator, &rule);
|
||||||
|
if (ret != RCL_RET_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check global rules if no local rule matched
|
||||||
|
if (NULL == rule && NULL != global_arguments) {
|
||||||
|
rcl_ret_t ret = _rcl_remap_first_match(
|
||||||
|
global_arguments->impl->remap_rules, global_arguments->impl->num_remap_rules, type_bitmask,
|
||||||
|
name, node_name, node_namespace, substitutions, allocator, &rule);
|
||||||
|
if (ret != RCL_RET_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Do the remapping
|
||||||
|
if (NULL != rule) {
|
||||||
|
if (rule->type & (RCL_TOPIC_REMAP | RCL_SERVICE_REMAP)) {
|
||||||
|
// topic and service rules need the replacement to be expanded to a FQN
|
||||||
|
rcl_ret_t ret = rcl_expand_topic_name(
|
||||||
|
rule->replacement, node_name, node_namespace, substitutions, allocator, output_name);
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// nodename and namespace rules don't need replacment expanded
|
||||||
|
*output_name = rcutils_strdup(rule->replacement, allocator);
|
||||||
|
}
|
||||||
|
if (NULL == *output_name) {
|
||||||
|
RCL_SET_ERROR_MSG("Failed to set output", allocator);
|
||||||
|
return RCL_RET_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RCL_RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_remap_topic_name(
|
||||||
|
const rcl_arguments_t * local_arguments,
|
||||||
|
const rcl_arguments_t * global_arguments,
|
||||||
|
const char * topic_name,
|
||||||
|
const char * node_name,
|
||||||
|
const char * node_namespace,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
char ** output_name)
|
||||||
|
{
|
||||||
|
RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "allocator is invalid", return RCL_RET_INVALID_ARGUMENT);
|
||||||
|
RCL_CHECK_ARGUMENT_FOR_NULL(topic_name, RCL_RET_INVALID_ARGUMENT, allocator);
|
||||||
|
|
||||||
|
rcutils_string_map_t substitutions = rcutils_get_zero_initialized_string_map();
|
||||||
|
rcutils_ret_t rcutils_ret = rcutils_string_map_init(&substitutions, 0, allocator);
|
||||||
|
rcl_ret_t ret = RCL_RET_ERROR;
|
||||||
|
if (RCUTILS_RET_OK == rcutils_ret) {
|
||||||
|
ret = rcl_get_default_topic_name_substitutions(&substitutions);
|
||||||
|
if (RCL_RET_OK == ret) {
|
||||||
|
ret = _rcl_remap_name(
|
||||||
|
local_arguments, global_arguments, RCL_TOPIC_REMAP, topic_name, node_name,
|
||||||
|
node_namespace, &substitutions, allocator, output_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (RCUTILS_RET_OK != rcutils_string_map_fini(&substitutions)) {
|
||||||
|
return RCL_RET_ERROR;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_remap_service_name(
|
||||||
|
const rcl_arguments_t * local_arguments,
|
||||||
|
const rcl_arguments_t * global_arguments,
|
||||||
|
const char * service_name,
|
||||||
|
const char * node_name,
|
||||||
|
const char * node_namespace,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
char ** output_name)
|
||||||
|
{
|
||||||
|
RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "allocator is invalid", return RCL_RET_INVALID_ARGUMENT);
|
||||||
|
RCL_CHECK_ARGUMENT_FOR_NULL(service_name, RCL_RET_INVALID_ARGUMENT, allocator);
|
||||||
|
|
||||||
|
rcutils_string_map_t substitutions = rcutils_get_zero_initialized_string_map();
|
||||||
|
rcutils_ret_t rcutils_ret = rcutils_string_map_init(&substitutions, 0, allocator);
|
||||||
|
rcl_ret_t ret = RCL_RET_ERROR;
|
||||||
|
if (rcutils_ret == RCUTILS_RET_OK) {
|
||||||
|
ret = rcl_get_default_topic_name_substitutions(&substitutions);
|
||||||
|
if (ret == RCL_RET_OK) {
|
||||||
|
ret = _rcl_remap_name(
|
||||||
|
local_arguments, global_arguments, RCL_SERVICE_REMAP, service_name, node_name,
|
||||||
|
node_namespace, &substitutions, allocator, output_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (RCUTILS_RET_OK != rcutils_string_map_fini(&substitutions)) {
|
||||||
|
return RCL_RET_ERROR;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_remap_node_name(
|
||||||
|
const rcl_arguments_t * local_arguments,
|
||||||
|
const rcl_arguments_t * global_arguments,
|
||||||
|
const char * node_name,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
char ** output_name)
|
||||||
|
{
|
||||||
|
RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "allocator is invalid", return RCL_RET_INVALID_ARGUMENT);
|
||||||
|
return _rcl_remap_name(
|
||||||
|
local_arguments, global_arguments, RCL_NODENAME_REMAP, NULL, node_name, NULL, NULL,
|
||||||
|
allocator, output_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_remap_node_namespace(
|
||||||
|
const rcl_arguments_t * local_arguments,
|
||||||
|
const rcl_arguments_t * global_arguments,
|
||||||
|
const char * node_name,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
char ** output_namespace)
|
||||||
|
{
|
||||||
|
RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "allocator is invalid", return RCL_RET_INVALID_ARGUMENT);
|
||||||
|
return _rcl_remap_name(
|
||||||
|
local_arguments, global_arguments, RCL_NAMESPACE_REMAP, NULL, node_name, NULL, NULL,
|
||||||
|
allocator, output_namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
80
rcl/src/rcl/remap_impl.h
Normal file
80
rcl/src/rcl/remap_impl.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
// Copyright 2018 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCL__REMAP_IMPL_H_
|
||||||
|
#define RCL__REMAP_IMPL_H_
|
||||||
|
|
||||||
|
#include "rcl/types.h"
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Enum doubles as a bitmask for rule sthat apply to both topics and services.
|
||||||
|
typedef enum rcl_remap_type_t
|
||||||
|
{
|
||||||
|
RCL_UNKNOWN_REMAP = 0,
|
||||||
|
RCL_TOPIC_REMAP = 1u << 0,
|
||||||
|
RCL_SERVICE_REMAP = 1u << 1,
|
||||||
|
RCL_NODENAME_REMAP = 1u << 2,
|
||||||
|
RCL_NAMESPACE_REMAP = 1u << 3
|
||||||
|
} rcl_remap_type_t;
|
||||||
|
|
||||||
|
typedef struct rcl_remap_t
|
||||||
|
{
|
||||||
|
/// Bitmask indicating what type of rule this is.
|
||||||
|
rcl_remap_type_t type;
|
||||||
|
/// A node name that this rule is limited to, or NULL if it applies to any node.
|
||||||
|
char * node_name;
|
||||||
|
/// Match portion of a rule, or NULL if node name or namespace replacement.
|
||||||
|
char * match;
|
||||||
|
/// Replacement portion of a rule.
|
||||||
|
char * replacement;
|
||||||
|
|
||||||
|
/// Allocator used to allocate objects in this struct
|
||||||
|
rcl_allocator_t allocator;
|
||||||
|
} rcl_remap_t;
|
||||||
|
|
||||||
|
/// Get an rcl_remap_t structure initialized with NULL.
|
||||||
|
rcl_remap_t
|
||||||
|
rcl_remap_get_zero_initialized();
|
||||||
|
|
||||||
|
/// Reclaim resources used in an rcl_remap_t structure.
|
||||||
|
/**
|
||||||
|
* <hr>
|
||||||
|
* Attribute | Adherence
|
||||||
|
* ------------------ | -------------
|
||||||
|
* Allocates Memory | No
|
||||||
|
* Thread-Safe | Yes
|
||||||
|
* Uses Atomics | No
|
||||||
|
* Lock-Free | Yes
|
||||||
|
*
|
||||||
|
* \param[in] rule A rule to deallocate back to a zero initialized state.
|
||||||
|
* \return `RCL_RET_OK` if the structure was free'd, or
|
||||||
|
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
|
||||||
|
* \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
|
||||||
|
* \return `RCL_RET_NODE_INVALID_NAME` if the name is invalid, or
|
||||||
|
* \return `RCL_RET_ERROR` if an unspecified error occurs.
|
||||||
|
*/
|
||||||
|
RCL_WARN_UNUSED
|
||||||
|
rcl_ret_t
|
||||||
|
rcl_remap_fini(
|
||||||
|
rcl_remap_t * rule);
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RCL__REMAP_IMPL_H_
|
|
@ -24,6 +24,7 @@ extern "C"
|
||||||
|
|
||||||
#include "rcl/error_handling.h"
|
#include "rcl/error_handling.h"
|
||||||
#include "rcl/expand_topic_name.h"
|
#include "rcl/expand_topic_name.h"
|
||||||
|
#include "rcl/remap.h"
|
||||||
#include "rcutils/logging_macros.h"
|
#include "rcutils/logging_macros.h"
|
||||||
#include "rmw/error_handling.h"
|
#include "rmw/error_handling.h"
|
||||||
#include "rmw/rmw.h"
|
#include "rmw/rmw.h"
|
||||||
|
@ -97,6 +98,7 @@ rcl_service_init(
|
||||||
return RCL_RET_ERROR;
|
return RCL_RET_ERROR;
|
||||||
}
|
}
|
||||||
char * expanded_service_name = NULL;
|
char * expanded_service_name = NULL;
|
||||||
|
char * remapped_service_name = NULL;
|
||||||
ret = rcl_expand_topic_name(
|
ret = rcl_expand_topic_name(
|
||||||
service_name,
|
service_name,
|
||||||
rcl_node_get_name(node),
|
rcl_node_get_name(node),
|
||||||
|
@ -107,35 +109,57 @@ rcl_service_init(
|
||||||
rcutils_ret = rcutils_string_map_fini(&substitutions_map);
|
rcutils_ret = rcutils_string_map_fini(&substitutions_map);
|
||||||
if (rcutils_ret != RCUTILS_RET_OK) {
|
if (rcutils_ret != RCUTILS_RET_OK) {
|
||||||
RCL_SET_ERROR_MSG(rcutils_get_error_string_safe(), *allocator)
|
RCL_SET_ERROR_MSG(rcutils_get_error_string_safe(), *allocator)
|
||||||
allocator->deallocate(expanded_service_name, allocator->state);
|
ret = RCL_RET_ERROR;
|
||||||
|
goto cleanup;
|
||||||
return RCL_RET_ERROR;
|
return RCL_RET_ERROR;
|
||||||
}
|
}
|
||||||
if (ret != RCL_RET_OK) {
|
if (ret != RCL_RET_OK) {
|
||||||
if (ret == RCL_RET_BAD_ALLOC) {
|
if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
|
||||||
return ret;
|
ret = RCL_RET_SERVICE_NAME_INVALID;
|
||||||
} else if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
|
|
||||||
return RCL_RET_SERVICE_NAME_INVALID;
|
|
||||||
} else {
|
} else {
|
||||||
return RCL_RET_ERROR;
|
ret = RCL_RET_ERROR;
|
||||||
}
|
}
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Expanded service name '%s'", expanded_service_name)
|
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Expanded service name '%s'", expanded_service_name)
|
||||||
|
|
||||||
|
const rcl_node_options_t * node_options = rcl_node_get_options(node);
|
||||||
|
if (NULL == node_options) {
|
||||||
|
ret = RCL_RET_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
rcl_arguments_t * global_args = NULL;
|
||||||
|
if (node_options->use_global_arguments) {
|
||||||
|
global_args = rcl_get_global_arguments();
|
||||||
|
}
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
&(node_options->arguments), global_args, expanded_service_name,
|
||||||
|
rcl_node_get_name(node), rcl_node_get_namespace(node), *allocator, &remapped_service_name);
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
goto fail;
|
||||||
|
} else if (NULL == remapped_service_name) {
|
||||||
|
remapped_service_name = expanded_service_name;
|
||||||
|
expanded_service_name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the expanded service name.
|
// Validate the expanded service name.
|
||||||
int validation_result;
|
int validation_result;
|
||||||
rmw_ret_t rmw_ret = rmw_validate_full_topic_name(expanded_service_name, &validation_result, NULL);
|
rmw_ret_t rmw_ret = rmw_validate_full_topic_name(remapped_service_name, &validation_result, NULL);
|
||||||
if (rmw_ret != RMW_RET_OK) {
|
if (rmw_ret != RMW_RET_OK) {
|
||||||
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
||||||
return RCL_RET_ERROR;
|
ret = RCL_RET_ERROR;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (validation_result != RMW_TOPIC_VALID) {
|
if (validation_result != RMW_TOPIC_VALID) {
|
||||||
RCL_SET_ERROR_MSG(rmw_full_topic_name_validation_result_string(validation_result), *allocator)
|
RCL_SET_ERROR_MSG(rmw_full_topic_name_validation_result_string(validation_result), *allocator)
|
||||||
return RCL_RET_SERVICE_NAME_INVALID;
|
ret = RCL_RET_SERVICE_NAME_INVALID;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
// Allocate space for the implementation struct.
|
// Allocate space for the implementation struct.
|
||||||
service->impl = (rcl_service_impl_t *)allocator->allocate(
|
service->impl = (rcl_service_impl_t *)allocator->allocate(
|
||||||
sizeof(rcl_service_impl_t), allocator->state);
|
sizeof(rcl_service_impl_t), allocator->state);
|
||||||
RCL_CHECK_FOR_NULL_WITH_MSG(
|
RCL_CHECK_FOR_NULL_WITH_MSG(
|
||||||
service->impl, "allocating memory failed", return RCL_RET_BAD_ALLOC, *allocator);
|
service->impl, "allocating memory failed", ret = RCL_RET_BAD_ALLOC; goto cleanup, *allocator);
|
||||||
|
|
||||||
if (RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL == options->qos.durability) {
|
if (RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL == options->qos.durability) {
|
||||||
RCUTILS_LOG_WARN_NAMED(
|
RCUTILS_LOG_WARN_NAMED(
|
||||||
|
@ -149,9 +173,8 @@ rcl_service_init(
|
||||||
service->impl->rmw_handle = rmw_create_service(
|
service->impl->rmw_handle = rmw_create_service(
|
||||||
rcl_node_get_rmw_handle(node),
|
rcl_node_get_rmw_handle(node),
|
||||||
type_support,
|
type_support,
|
||||||
expanded_service_name,
|
remapped_service_name,
|
||||||
&options->qos);
|
&options->qos);
|
||||||
allocator->deallocate(expanded_service_name, allocator->state);
|
|
||||||
if (!service->impl->rmw_handle) {
|
if (!service->impl->rmw_handle) {
|
||||||
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -159,12 +182,22 @@ rcl_service_init(
|
||||||
// options
|
// options
|
||||||
service->impl->options = *options;
|
service->impl->options = *options;
|
||||||
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Service initialized")
|
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Service initialized")
|
||||||
return RCL_RET_OK;
|
ret = RCL_RET_OK;
|
||||||
|
goto cleanup;
|
||||||
fail:
|
fail:
|
||||||
if (service->impl) {
|
if (service->impl) {
|
||||||
allocator->deallocate(service->impl, allocator->state);
|
allocator->deallocate(service->impl, allocator->state);
|
||||||
}
|
}
|
||||||
return fail_ret;
|
ret = fail_ret;
|
||||||
|
// Fall through to clean up
|
||||||
|
cleanup:
|
||||||
|
if (NULL != expanded_service_name) {
|
||||||
|
allocator->deallocate(expanded_service_name, allocator->state);
|
||||||
|
}
|
||||||
|
if (NULL != remapped_service_name) {
|
||||||
|
allocator->deallocate(remapped_service_name, allocator->state);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcl_ret_t
|
rcl_ret_t
|
||||||
|
|
|
@ -23,6 +23,7 @@ extern "C"
|
||||||
|
|
||||||
#include "rcl/error_handling.h"
|
#include "rcl/error_handling.h"
|
||||||
#include "rcl/expand_topic_name.h"
|
#include "rcl/expand_topic_name.h"
|
||||||
|
#include "rcl/remap.h"
|
||||||
#include "rcutils/logging_macros.h"
|
#include "rcutils/logging_macros.h"
|
||||||
#include "rmw/error_handling.h"
|
#include "rmw/error_handling.h"
|
||||||
#include "rmw/rmw.h"
|
#include "rmw/rmw.h"
|
||||||
|
@ -96,6 +97,7 @@ rcl_subscription_init(
|
||||||
return RCL_RET_ERROR;
|
return RCL_RET_ERROR;
|
||||||
}
|
}
|
||||||
char * expanded_topic_name = NULL;
|
char * expanded_topic_name = NULL;
|
||||||
|
char * remapped_topic_name = NULL;
|
||||||
ret = rcl_expand_topic_name(
|
ret = rcl_expand_topic_name(
|
||||||
topic_name,
|
topic_name,
|
||||||
rcl_node_get_name(node),
|
rcl_node_get_name(node),
|
||||||
|
@ -106,45 +108,66 @@ rcl_subscription_init(
|
||||||
rcutils_ret = rcutils_string_map_fini(&substitutions_map);
|
rcutils_ret = rcutils_string_map_fini(&substitutions_map);
|
||||||
if (rcutils_ret != RCUTILS_RET_OK) {
|
if (rcutils_ret != RCUTILS_RET_OK) {
|
||||||
RCL_SET_ERROR_MSG(rcutils_get_error_string_safe(), *allocator)
|
RCL_SET_ERROR_MSG(rcutils_get_error_string_safe(), *allocator)
|
||||||
allocator->deallocate(expanded_topic_name, allocator->state);
|
ret = RCL_RET_ERROR;
|
||||||
return RCL_RET_ERROR;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (ret != RCL_RET_OK) {
|
if (ret != RCL_RET_OK) {
|
||||||
if (ret == RCL_RET_BAD_ALLOC) {
|
if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
|
||||||
return ret;
|
ret = RCL_RET_TOPIC_NAME_INVALID;
|
||||||
} else if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
|
|
||||||
return RCL_RET_TOPIC_NAME_INVALID;
|
|
||||||
} else {
|
} else {
|
||||||
return RCL_RET_ERROR;
|
ret = RCL_RET_ERROR;
|
||||||
}
|
}
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Expanded topic name '%s'", expanded_topic_name)
|
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Expanded topic name '%s'", expanded_topic_name)
|
||||||
|
|
||||||
|
const rcl_node_options_t * node_options = rcl_node_get_options(node);
|
||||||
|
if (NULL == node_options) {
|
||||||
|
ret = RCL_RET_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
rcl_arguments_t * global_args = NULL;
|
||||||
|
if (node_options->use_global_arguments) {
|
||||||
|
global_args = rcl_get_global_arguments();
|
||||||
|
}
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
&(node_options->arguments), global_args, expanded_topic_name,
|
||||||
|
rcl_node_get_name(node), rcl_node_get_namespace(node), *allocator, &remapped_topic_name);
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
goto fail;
|
||||||
|
} else if (NULL == remapped_topic_name) {
|
||||||
|
remapped_topic_name = expanded_topic_name;
|
||||||
|
expanded_topic_name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the expanded topic name.
|
// Validate the expanded topic name.
|
||||||
int validation_result;
|
int validation_result;
|
||||||
rmw_ret_t rmw_ret = rmw_validate_full_topic_name(expanded_topic_name, &validation_result, NULL);
|
rmw_ret_t rmw_ret = rmw_validate_full_topic_name(remapped_topic_name, &validation_result, NULL);
|
||||||
if (rmw_ret != RMW_RET_OK) {
|
if (rmw_ret != RMW_RET_OK) {
|
||||||
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
||||||
return RCL_RET_ERROR;
|
ret = RCL_RET_ERROR;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (validation_result != RMW_TOPIC_VALID) {
|
if (validation_result != RMW_TOPIC_VALID) {
|
||||||
RCL_SET_ERROR_MSG(rmw_full_topic_name_validation_result_string(validation_result), *allocator)
|
RCL_SET_ERROR_MSG(rmw_full_topic_name_validation_result_string(validation_result), *allocator)
|
||||||
return RCL_RET_TOPIC_NAME_INVALID;
|
ret = RCL_RET_TOPIC_NAME_INVALID;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
// Allocate memory for the implementation struct.
|
// Allocate memory for the implementation struct.
|
||||||
subscription->impl = (rcl_subscription_impl_t *)allocator->allocate(
|
subscription->impl = (rcl_subscription_impl_t *)allocator->allocate(
|
||||||
sizeof(rcl_subscription_impl_t), allocator->state);
|
sizeof(rcl_subscription_impl_t), allocator->state);
|
||||||
RCL_CHECK_FOR_NULL_WITH_MSG(
|
RCL_CHECK_FOR_NULL_WITH_MSG(
|
||||||
subscription->impl, "allocating memory failed", return RCL_RET_BAD_ALLOC, *allocator);
|
subscription->impl, "allocating memory failed", ret = RCL_RET_BAD_ALLOC; goto cleanup,
|
||||||
|
*allocator);
|
||||||
// Fill out the implemenation struct.
|
// Fill out the implemenation struct.
|
||||||
// rmw_handle
|
// rmw_handle
|
||||||
// TODO(wjwwood): pass allocator once supported in rmw api.
|
// TODO(wjwwood): pass allocator once supported in rmw api.
|
||||||
subscription->impl->rmw_handle = rmw_create_subscription(
|
subscription->impl->rmw_handle = rmw_create_subscription(
|
||||||
rcl_node_get_rmw_handle(node),
|
rcl_node_get_rmw_handle(node),
|
||||||
type_support,
|
type_support,
|
||||||
expanded_topic_name,
|
remapped_topic_name,
|
||||||
&(options->qos),
|
&(options->qos),
|
||||||
options->ignore_local_publications);
|
options->ignore_local_publications);
|
||||||
allocator->deallocate(expanded_topic_name, allocator->state);
|
|
||||||
if (!subscription->impl->rmw_handle) {
|
if (!subscription->impl->rmw_handle) {
|
||||||
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -152,12 +175,22 @@ rcl_subscription_init(
|
||||||
// options
|
// options
|
||||||
subscription->impl->options = *options;
|
subscription->impl->options = *options;
|
||||||
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Subscription initialized")
|
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Subscription initialized")
|
||||||
return RCL_RET_OK;
|
ret = RCL_RET_OK;
|
||||||
|
goto cleanup;
|
||||||
fail:
|
fail:
|
||||||
if (subscription->impl) {
|
if (subscription->impl) {
|
||||||
allocator->deallocate(subscription->impl, allocator->state);
|
allocator->deallocate(subscription->impl, allocator->state);
|
||||||
}
|
}
|
||||||
return fail_ret;
|
ret = fail_ret;
|
||||||
|
// Fall through to cleanup
|
||||||
|
cleanup:
|
||||||
|
if (NULL != expanded_topic_name) {
|
||||||
|
allocator->deallocate(expanded_topic_name, allocator->state);
|
||||||
|
}
|
||||||
|
if (NULL != remapped_topic_name) {
|
||||||
|
allocator->deallocate(remapped_topic_name, allocator->state);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcl_ret_t
|
rcl_ret_t
|
||||||
|
|
|
@ -100,6 +100,29 @@ function(test_target_function)
|
||||||
AMENT_DEPENDENCIES ${rmw_implementation}
|
AMENT_DEPENDENCIES ${rmw_implementation}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
rcl_add_custom_gtest(test_arguments${target_suffix}
|
||||||
|
SRCS rcl/test_arguments.cpp
|
||||||
|
ENV ${extra_test_env}
|
||||||
|
APPEND_LIBRARY_DIRS ${extra_lib_dirs}
|
||||||
|
LIBRARIES ${PROJECT_NAME} ${extra_test_libraries}
|
||||||
|
)
|
||||||
|
|
||||||
|
rcl_add_custom_gtest(test_remap${target_suffix}
|
||||||
|
SRCS rcl/test_remap.cpp
|
||||||
|
ENV ${extra_test_env}
|
||||||
|
APPEND_LIBRARY_DIRS ${extra_lib_dirs}
|
||||||
|
LIBRARIES ${PROJECT_NAME} ${extra_test_libraries}
|
||||||
|
)
|
||||||
|
|
||||||
|
rcl_add_custom_gtest(test_remap_integration${target_suffix}
|
||||||
|
SRCS rcl/test_remap_integration.cpp
|
||||||
|
TIMEOUT 200
|
||||||
|
ENV ${extra_test_env}
|
||||||
|
APPEND_LIBRARY_DIRS ${extra_lib_dirs}
|
||||||
|
LIBRARIES ${PROJECT_NAME} ${extra_test_libraries}
|
||||||
|
AMENT_DEPENDENCIES "std_msgs" "example_interfaces"
|
||||||
|
)
|
||||||
|
|
||||||
rcl_add_custom_gtest(test_guard_condition${target_suffix}
|
rcl_add_custom_gtest(test_guard_condition${target_suffix}
|
||||||
SRCS rcl/test_guard_condition.cpp
|
SRCS rcl/test_guard_condition.cpp
|
||||||
ENV ${extra_test_env}
|
ENV ${extra_test_env}
|
||||||
|
|
75
rcl/test/rcl/arg_macros.hpp
Normal file
75
rcl/test/rcl/arg_macros.hpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
// Copyright 2018 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCL__ARG_MACROS_HPP_
|
||||||
|
#define RCL__ARG_MACROS_HPP_
|
||||||
|
|
||||||
|
#include "rcl/error_handling.h"
|
||||||
|
#include "rcl/rcl.h"
|
||||||
|
#include "rcutils/strdup.h"
|
||||||
|
|
||||||
|
#include "../scope_exit.hpp"
|
||||||
|
|
||||||
|
/// Helper to get around non-const args passed to rcl_init().
|
||||||
|
char **
|
||||||
|
copy_args(int argc, const char ** args)
|
||||||
|
{
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||||
|
char ** copy = static_cast<char **>(allocator.allocate(sizeof(char *) * argc, allocator.state));
|
||||||
|
for (int i = 0; i < argc; ++i) {
|
||||||
|
copy[i] = rcutils_strdup(args[i], allocator);
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroy args allocated by copy_args.
|
||||||
|
void
|
||||||
|
destroy_args(int argc, char ** args)
|
||||||
|
{
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||||
|
for (int i = 0; i < argc; ++i) {
|
||||||
|
allocator.deallocate(args[i], allocator.state);
|
||||||
|
}
|
||||||
|
allocator.deallocate(args, allocator.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SCOPE_GLOBAL_ARGS(argc, argv, ...) \
|
||||||
|
{ \
|
||||||
|
const char * const_argv[] = {__VA_ARGS__}; \
|
||||||
|
argc = (sizeof(const_argv) / sizeof(const char *)); \
|
||||||
|
argv = copy_args(argc, const_argv); \
|
||||||
|
rcl_ret_t ret = rcl_init(argc, argv, rcl_get_default_allocator()); \
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe(); \
|
||||||
|
} \
|
||||||
|
auto __scope_global_args_exit = make_scope_exit( \
|
||||||
|
[argc, argv] { \
|
||||||
|
destroy_args(argc, argv); \
|
||||||
|
rcl_ret_t ret = rcl_shutdown(); \
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe(); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define SCOPE_ARGS(local_arguments, ...) \
|
||||||
|
{ \
|
||||||
|
const char * local_argv[] = {__VA_ARGS__}; \
|
||||||
|
unsigned int local_argc = (sizeof(local_argv) / sizeof(const char *)); \
|
||||||
|
rcl_ret_t ret = rcl_parse_arguments( \
|
||||||
|
local_argc, local_argv, rcl_get_default_allocator(), &local_arguments); \
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe(); \
|
||||||
|
} \
|
||||||
|
auto __scope_ ## local_arguments ## _exit = make_scope_exit( \
|
||||||
|
[&local_arguments] { \
|
||||||
|
ASSERT_EQ(RCL_RET_OK, rcl_arguments_fini(&local_arguments)); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif // RCL__ARG_MACROS_HPP_
|
191
rcl/test/rcl/test_arguments.cpp
Normal file
191
rcl/test/rcl/test_arguments.cpp
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
// Copyright 2018 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "rcl/rcl.h"
|
||||||
|
#include "rcl/arguments.h"
|
||||||
|
|
||||||
|
#include "rcl/error_handling.h"
|
||||||
|
|
||||||
|
#ifdef RMW_IMPLEMENTATION
|
||||||
|
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
|
||||||
|
# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX)
|
||||||
|
#else
|
||||||
|
# define CLASSNAME(NAME, SUFFIX) NAME
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CLASSNAME (TestArgumentsFixture, RMW_IMPLEMENTATION) : public ::testing::Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void SetUp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define EXPECT_UNPARSED(parsed_args, ...) \
|
||||||
|
do { \
|
||||||
|
int expect_unparsed[] = {__VA_ARGS__}; \
|
||||||
|
int expect_num_unparsed = sizeof(expect_unparsed) / sizeof(int); \
|
||||||
|
rcl_allocator_t alloc = rcl_get_default_allocator(); \
|
||||||
|
int actual_num_unparsed = rcl_arguments_get_count_unparsed(&parsed_args); \
|
||||||
|
int * actual_unparsed = NULL; \
|
||||||
|
if (actual_num_unparsed > 0) { \
|
||||||
|
rcl_ret_t ret = rcl_arguments_get_unparsed(&parsed_args, alloc, &actual_unparsed); \
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret); \
|
||||||
|
} \
|
||||||
|
std::stringstream expected; \
|
||||||
|
expected << "["; \
|
||||||
|
for (int e = 0; e < expect_num_unparsed; ++e) { \
|
||||||
|
expected << expect_unparsed[e] << ", "; \
|
||||||
|
} \
|
||||||
|
expected << "]"; \
|
||||||
|
std::stringstream actual; \
|
||||||
|
actual << "["; \
|
||||||
|
for (int a = 0; a < actual_num_unparsed; ++a) { \
|
||||||
|
actual << actual_unparsed[a] << ", "; \
|
||||||
|
} \
|
||||||
|
actual << "]"; \
|
||||||
|
if (NULL != actual_unparsed) { \
|
||||||
|
alloc.deallocate(actual_unparsed, alloc.state); \
|
||||||
|
} \
|
||||||
|
EXPECT_STREQ(expected.str().c_str(), actual.str().c_str()); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_valid_arg(const char * arg)
|
||||||
|
{
|
||||||
|
const char * argv[] = {arg};
|
||||||
|
rcl_arguments_t parsed_args;
|
||||||
|
rcl_ret_t ret = rcl_parse_arguments(1, argv, rcl_get_default_allocator(), &parsed_args);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
bool is_valid = 0 == rcl_arguments_get_count_unparsed(&parsed_args);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_arguments_fini(&parsed_args));
|
||||||
|
return is_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), check_valid_vs_invalid_args) {
|
||||||
|
EXPECT_TRUE(is_valid_arg("__node:=node_name"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("old_name:__node:=node_name"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("old_name:__node:=nodename123"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("__node:=nodename123"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("__ns:=/foo/bar"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("__ns:=/"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("nodename:__ns:=/foobar"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("foo:=bar"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("~/foo:=~/bar"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("/foo/bar:=bar"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("foo:=/bar"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("/foo123:=/bar123"));
|
||||||
|
EXPECT_TRUE(is_valid_arg("node:/foo123:=/bar123"));
|
||||||
|
|
||||||
|
EXPECT_FALSE(is_valid_arg(":="));
|
||||||
|
EXPECT_FALSE(is_valid_arg("foo:="));
|
||||||
|
EXPECT_FALSE(is_valid_arg(":=bar"));
|
||||||
|
EXPECT_FALSE(is_valid_arg("__ns:="));
|
||||||
|
EXPECT_FALSE(is_valid_arg("__node:="));
|
||||||
|
EXPECT_FALSE(is_valid_arg("__node:=/foo/bar"));
|
||||||
|
EXPECT_FALSE(is_valid_arg("__ns:=foo"));
|
||||||
|
EXPECT_FALSE(is_valid_arg(":__node:=nodename"));
|
||||||
|
EXPECT_FALSE(is_valid_arg("~:__node:=nodename"));
|
||||||
|
EXPECT_FALSE(is_valid_arg("}foo:=/bar"));
|
||||||
|
EXPECT_FALSE(is_valid_arg("f oo:=/bar"));
|
||||||
|
EXPECT_FALSE(is_valid_arg("foo:=/b ar"));
|
||||||
|
EXPECT_FALSE(is_valid_arg("f{oo:=/bar"));
|
||||||
|
EXPECT_FALSE(is_valid_arg("foo:=/b}ar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_no_args) {
|
||||||
|
rcl_arguments_t parsed_args;
|
||||||
|
rcl_ret_t ret = rcl_parse_arguments(0, NULL, rcl_get_default_allocator(), &parsed_args);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_EQ(0, rcl_arguments_get_count_unparsed(&parsed_args));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_arguments_fini(&parsed_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_null_args) {
|
||||||
|
int argc = 1;
|
||||||
|
rcl_arguments_t parsed_args;
|
||||||
|
rcl_ret_t ret = rcl_parse_arguments(argc, NULL, rcl_get_default_allocator(), &parsed_args);
|
||||||
|
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret) << rcl_get_error_string_safe();
|
||||||
|
rcl_reset_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_null_args_output) {
|
||||||
|
const char * argv[] = {"process_name"};
|
||||||
|
int argc = sizeof(argv) / sizeof(const char *);
|
||||||
|
rcl_ret_t ret = rcl_parse_arguments(argc, argv, rcl_get_default_allocator(), NULL);
|
||||||
|
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret) << rcl_get_error_string_safe();
|
||||||
|
rcl_reset_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_one_remap) {
|
||||||
|
const char * argv[] = {"process_name", "/foo/bar:=/fiz/buz"};
|
||||||
|
int argc = sizeof(argv) / sizeof(const char *);
|
||||||
|
rcl_arguments_t parsed_args;
|
||||||
|
rcl_ret_t ret;
|
||||||
|
ret = rcl_parse_arguments(argc, argv, rcl_get_default_allocator(), &parsed_args);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_UNPARSED(parsed_args, 0);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_arguments_fini(&parsed_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_mix_valid_invalid_rules) {
|
||||||
|
const char * argv[] = {"process_name", "/foo/bar:=", "bar:=/fiz/buz", "}bar:=fiz"};
|
||||||
|
int argc = sizeof(argv) / sizeof(const char *);
|
||||||
|
rcl_arguments_t parsed_args;
|
||||||
|
rcl_ret_t ret;
|
||||||
|
ret = rcl_parse_arguments(argc, argv, rcl_get_default_allocator(), &parsed_args);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_UNPARSED(parsed_args, 0, 1, 3);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_arguments_fini(&parsed_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_two_namespace) {
|
||||||
|
const char * argv[] = {"process_name", "__ns:=/foo/bar", "__ns:=/fiz/buz"};
|
||||||
|
int argc = sizeof(argv) / sizeof(const char *);
|
||||||
|
rcl_arguments_t parsed_args;
|
||||||
|
rcl_ret_t ret;
|
||||||
|
ret = rcl_parse_arguments(argc, argv, rcl_get_default_allocator(), &parsed_args);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_UNPARSED(parsed_args, 0);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_arguments_fini(&parsed_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_fini_null) {
|
||||||
|
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, rcl_arguments_fini(NULL));
|
||||||
|
rcl_reset_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_fini_impl_null) {
|
||||||
|
rcl_arguments_t parsed_args;
|
||||||
|
parsed_args.impl = NULL;
|
||||||
|
EXPECT_EQ(RCL_RET_ERROR, rcl_arguments_fini(&parsed_args));
|
||||||
|
rcl_reset_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestArgumentsFixture, RMW_IMPLEMENTATION), test_fini_twice) {
|
||||||
|
const char * argv[] = {"process_name"};
|
||||||
|
int argc = sizeof(argv) / sizeof(const char *);
|
||||||
|
rcl_arguments_t parsed_args;
|
||||||
|
ASSERT_EQ(RCL_RET_OK, rcl_parse_arguments(argc, argv, rcl_get_default_allocator(), &parsed_args));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_arguments_fini(&parsed_args));
|
||||||
|
EXPECT_EQ(RCL_RET_ERROR, rcl_arguments_fini(&parsed_args));
|
||||||
|
rcl_reset_error();
|
||||||
|
}
|
467
rcl/test/rcl/test_remap.cpp
Normal file
467
rcl/test/rcl/test_remap.cpp
Normal file
|
@ -0,0 +1,467 @@
|
||||||
|
// Copyright 2018 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "rcl/rcl.h"
|
||||||
|
#include "rcl/remap.h"
|
||||||
|
#include "rcl/error_handling.h"
|
||||||
|
|
||||||
|
#include "./arg_macros.hpp"
|
||||||
|
|
||||||
|
#ifdef RMW_IMPLEMENTATION
|
||||||
|
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
|
||||||
|
# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX)
|
||||||
|
#else
|
||||||
|
# define CLASSNAME(NAME, SUFFIX) NAME
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CLASSNAME (TestRemapFixture, RMW_IMPLEMENTATION) : public ::testing::Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void SetUp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), global_namespace_replacement) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name", "__ns:=/foo/bar");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_namespace(
|
||||||
|
NULL, &global_arguments, "NodeName", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/foo/bar", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), nodename_prefix_namespace_remap) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(
|
||||||
|
global_arguments,
|
||||||
|
"process_name", "Node1:__ns:=/foo/bar", "Node2:__ns:=/this_one", "Node3:__ns:=/bar/foo");
|
||||||
|
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_namespace(
|
||||||
|
NULL, &global_arguments, "Node1", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/foo/bar", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_namespace(
|
||||||
|
NULL, &global_arguments, "Node2", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/this_one", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_namespace(
|
||||||
|
NULL, &global_arguments, "Node3", 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_namespace_replacement) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_namespace(
|
||||||
|
NULL, &global_arguments, "NodeName", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_EQ(NULL, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), local_namespace_replacement_before_global) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name", "__ns:=/global_args");
|
||||||
|
rcl_arguments_t local_arguments;
|
||||||
|
SCOPE_ARGS(local_arguments, "process_name", "__ns:=/local_args");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_namespace(
|
||||||
|
&local_arguments, &global_arguments, "NodeName", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/local_args", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), no_use_global_namespace_replacement) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t local_arguments;
|
||||||
|
SCOPE_ARGS(local_arguments, "process_name");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_namespace(
|
||||||
|
&local_arguments, NULL, "NodeName", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_EQ(NULL, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), other_rules_before_namespace_rule) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(
|
||||||
|
global_arguments, "process_name", "/foobar:=/foo/bar", "__ns:=/namespace", "__node:=new_name");
|
||||||
|
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_namespace(NULL, &global_arguments, "NodeName", allocator, &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/namespace", output);
|
||||||
|
allocator.deallocate(output, allocator.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), global_topic_name_replacement) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name", "/bar/foo:=/foo/bar");
|
||||||
|
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
NULL, &global_arguments, "/bar/foo", "NodeName", "/", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
ASSERT_STREQ("/foo/bar", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
NULL, &global_arguments, "/foo/bar", "NodeName", "/", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_EQ(NULL, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), relative_topic_name_remap) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name", "foo:=bar");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
NULL, &global_arguments, "/ns/foo", "NodeName", "/ns", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
ASSERT_STREQ("/ns/bar", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), nodename_prefix_topic_remap) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(
|
||||||
|
global_arguments,
|
||||||
|
"process_name", "Node1:/foo:=/foo/bar", "Node2:/foo:=/this_one", "Node3:/foo:=/bar/foo");
|
||||||
|
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
NULL, &global_arguments, "/foo", "Node1", "/", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/foo/bar", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
NULL, &global_arguments, "/foo", "Node2", "/", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/this_one", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
NULL, &global_arguments, "/foo", "Node3", "/", 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) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t local_arguments;
|
||||||
|
SCOPE_ARGS(local_arguments, "process_name");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
&local_arguments, NULL, "/bar/foo", "NodeName", "/", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_EQ(NULL, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), no_topic_name_replacement) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
NULL, &global_arguments, "/bar/foo", "NodeName", "/", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_EQ(NULL, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), local_topic_replacement_before_global) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name", "/bar/foo:=/foo/global_args");
|
||||||
|
rcl_arguments_t local_arguments;
|
||||||
|
SCOPE_ARGS(local_arguments, "process_name", "/bar/foo:=/foo/local_args");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
&local_arguments, &global_arguments, "/bar/foo", "NodeName", "/", rcl_get_default_allocator(),
|
||||||
|
&output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/foo/local_args", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), other_rules_before_topic_rule) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(
|
||||||
|
global_arguments, "process_name", "__ns:=/namespace", "__node:=remap_name",
|
||||||
|
"/foobar:=/foo/bar");
|
||||||
|
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_topic_name(
|
||||||
|
NULL, &global_arguments, "/foobar", "NodeName", "/", allocator, &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/foo/bar", output);
|
||||||
|
allocator.deallocate(output, allocator.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), global_service_name_replacement) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name", "/bar/foo:=/foo/bar");
|
||||||
|
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
NULL, &global_arguments, "/bar/foo", "NodeName", "/", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
ASSERT_STREQ("/foo/bar", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
NULL, &global_arguments, "/foobar", "NodeName", "/", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_EQ(NULL, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), relative_service_name_remap) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name", "foo:=bar");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
NULL, &global_arguments, "/ns/foo", "NodeName", "/ns", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
ASSERT_STREQ("/ns/bar", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), nodename_prefix_service_remap) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(
|
||||||
|
global_arguments,
|
||||||
|
"process_name", "Node1:/foo:=/foo/bar", "Node2:/foo:=/this_one", "Node3:/foo:=/bar/foo");
|
||||||
|
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
NULL, &global_arguments, "/foo", "Node1", "/", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/foo/bar", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
NULL, &global_arguments, "/foo", "Node2", "/", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/this_one", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
NULL, &global_arguments, "/foo", "Node3", "/", 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) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t local_arguments;
|
||||||
|
SCOPE_ARGS(local_arguments, "process_name");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
&local_arguments, NULL, "/bar/foo", "NodeName", "/", rcl_get_default_allocator(),
|
||||||
|
&output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_EQ(NULL, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), no_service_name_replacement) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
NULL, &global_arguments, "/bar/foo", "NodeName", "/", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_EQ(NULL, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), local_service_replacement_before_global) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name", "/bar/foo:=/foo/global_args");
|
||||||
|
rcl_arguments_t local_arguments;
|
||||||
|
SCOPE_ARGS(local_arguments, "process_name", "/bar/foo:=/foo/local_args");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
&local_arguments, &global_arguments, "/bar/foo", "NodeName", "/", rcl_get_default_allocator(),
|
||||||
|
&output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/foo/local_args", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), other_rules_before_service_rule) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(
|
||||||
|
global_arguments, "process_name", "__ns:=/namespace", "__node:=remap_name",
|
||||||
|
"/foobar:=/foo/bar");
|
||||||
|
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_service_name(
|
||||||
|
NULL, &global_arguments, "/foobar", "NodeName", "/", allocator, &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("/foo/bar", output);
|
||||||
|
allocator.deallocate(output, allocator.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), global_nodename_replacement) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name", "__node:=globalname");
|
||||||
|
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_name(NULL, &global_arguments, "NodeName", allocator, &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("globalname", output);
|
||||||
|
allocator.deallocate(output, allocator.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), no_nodename_replacement) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_name(NULL, &global_arguments, "NodeName", rcl_get_default_allocator(),
|
||||||
|
&output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_EQ(NULL, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), local_nodename_replacement_before_global) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name", "__node:=global_name");
|
||||||
|
rcl_arguments_t local_arguments;
|
||||||
|
SCOPE_ARGS(local_arguments, "process_name", "__node:=local_name");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_name(
|
||||||
|
&local_arguments, &global_arguments, "NodeName", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("local_name", output);
|
||||||
|
rcl_get_default_allocator().deallocate(output, rcl_get_default_allocator().state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), no_use_global_nodename_replacement) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t local_arguments;
|
||||||
|
SCOPE_ARGS(local_arguments, "process_name");
|
||||||
|
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_name(
|
||||||
|
&local_arguments, NULL, "NodeName", rcl_get_default_allocator(), &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_EQ(NULL, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), use_first_nodename_rule) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(global_arguments, "process_name", "__node:=firstname", "__node:=secondname");
|
||||||
|
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_name(NULL, &global_arguments, "NodeName", allocator, &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("firstname", output);
|
||||||
|
allocator.deallocate(output, allocator.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapFixture, RMW_IMPLEMENTATION), other_rules_before_nodename_rule) {
|
||||||
|
rcl_ret_t ret;
|
||||||
|
rcl_arguments_t global_arguments;
|
||||||
|
SCOPE_ARGS(
|
||||||
|
global_arguments, "process_name", "/foobar:=/foo", "__ns:=/namespace", "__node:=remap_name");
|
||||||
|
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||||
|
char * output = NULL;
|
||||||
|
ret = rcl_remap_node_name(NULL, &global_arguments, "NodeName", allocator, &output);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret);
|
||||||
|
EXPECT_STREQ("remap_name", output);
|
||||||
|
allocator.deallocate(output, allocator.state);
|
||||||
|
}
|
289
rcl/test/rcl/test_remap_integration.cpp
Normal file
289
rcl/test/rcl/test_remap_integration.cpp
Normal file
|
@ -0,0 +1,289 @@
|
||||||
|
// Copyright 2018 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "example_interfaces/srv/add_two_ints.h"
|
||||||
|
#include "rcl/rcl.h"
|
||||||
|
#include "rcl/remap.h"
|
||||||
|
#include "rcl/error_handling.h"
|
||||||
|
#include "std_msgs/msg/int64.h"
|
||||||
|
|
||||||
|
#include "./arg_macros.hpp"
|
||||||
|
|
||||||
|
#ifdef RMW_IMPLEMENTATION
|
||||||
|
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
|
||||||
|
# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX)
|
||||||
|
#else
|
||||||
|
# define CLASSNAME(NAME, SUFFIX) NAME
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CLASSNAME (TestRemapIntegrationFixture, RMW_IMPLEMENTATION) : public ::testing::Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void SetUp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapIntegrationFixture, RMW_IMPLEMENTATION), remap_using_global_rule) {
|
||||||
|
int argc;
|
||||||
|
char ** argv;
|
||||||
|
SCOPE_GLOBAL_ARGS(
|
||||||
|
argc, argv, "process_name", "__node:=new_name", "__ns:=/new_ns", "/foo/bar:=/bar/foo");
|
||||||
|
|
||||||
|
rcl_node_t node = rcl_get_zero_initialized_node();
|
||||||
|
rcl_node_options_t default_options = rcl_node_get_default_options();
|
||||||
|
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "/original_ns", &default_options));
|
||||||
|
|
||||||
|
{ // Node name gets remapped
|
||||||
|
EXPECT_STREQ("new_name", rcl_node_get_name(&node));
|
||||||
|
}
|
||||||
|
{ // Node namespace gets remapped
|
||||||
|
EXPECT_STREQ("/new_ns", rcl_node_get_namespace(&node));
|
||||||
|
}
|
||||||
|
{ // Logger name gets remapped
|
||||||
|
EXPECT_STREQ("new_ns.new_name", rcl_node_get_logger_name(&node));
|
||||||
|
}
|
||||||
|
{ // Publisher topic gets remapped
|
||||||
|
const rosidl_message_type_support_t * ts = ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int64);
|
||||||
|
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||||
|
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||||
|
rcl_ret_t ret = rcl_publisher_init(&publisher, &node, ts, "/foo/bar", &publisher_options);
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/bar/foo", rcl_publisher_get_topic_name(&publisher));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_publisher_fini(&publisher, &node));
|
||||||
|
}
|
||||||
|
{ // Subscription topic gets remapped
|
||||||
|
const rosidl_message_type_support_t * ts = ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int64);
|
||||||
|
rcl_subscription_options_t subscription_options = rcl_subscription_get_default_options();
|
||||||
|
rcl_subscription_t subscription = rcl_get_zero_initialized_subscription();
|
||||||
|
rcl_ret_t ret = rcl_subscription_init(
|
||||||
|
&subscription, &node, ts, "/foo/bar", &subscription_options);
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/bar/foo", rcl_subscription_get_topic_name(&subscription));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_subscription_fini(&subscription, &node));
|
||||||
|
}
|
||||||
|
{ // Client service name gets remapped
|
||||||
|
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
|
||||||
|
example_interfaces, AddTwoInts);
|
||||||
|
rcl_client_options_t client_options = rcl_client_get_default_options();
|
||||||
|
rcl_client_t client = rcl_get_zero_initialized_client();
|
||||||
|
rcl_ret_t ret = rcl_client_init(&client, &node, ts, "/foo/bar", &client_options);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/bar/foo", rcl_client_get_service_name(&client));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_client_fini(&client, &node));
|
||||||
|
}
|
||||||
|
{ // Server service name gets remapped
|
||||||
|
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
|
||||||
|
example_interfaces, AddTwoInts);
|
||||||
|
rcl_service_options_t service_options = rcl_service_get_default_options();
|
||||||
|
rcl_service_t service = rcl_get_zero_initialized_service();
|
||||||
|
rcl_ret_t ret = rcl_service_init(&service, &node, ts, "/foo/bar", &service_options);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/bar/foo", rcl_service_get_service_name(&service));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_service_fini(&service, &node));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_node_fini(&node));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapIntegrationFixture, RMW_IMPLEMENTATION), ignore_global_rules) {
|
||||||
|
int argc;
|
||||||
|
char ** argv;
|
||||||
|
SCOPE_GLOBAL_ARGS(
|
||||||
|
argc, argv, "process_name", "__node:=new_name", "__ns:=/new_ns", "/foo/bar:=/bar/foo");
|
||||||
|
rcl_arguments_t local_arguments;
|
||||||
|
SCOPE_ARGS(local_arguments, "local_process_name");
|
||||||
|
|
||||||
|
rcl_node_t node = rcl_get_zero_initialized_node();
|
||||||
|
rcl_node_options_t options = rcl_node_get_default_options();
|
||||||
|
options.use_global_arguments = false;
|
||||||
|
options.arguments = local_arguments;
|
||||||
|
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "/original_ns", &options));
|
||||||
|
|
||||||
|
{ // Node name does not get remapped
|
||||||
|
EXPECT_STREQ("original_name", rcl_node_get_name(&node));
|
||||||
|
}
|
||||||
|
{ // Node namespace does not get remapped
|
||||||
|
EXPECT_STREQ("/original_ns", rcl_node_get_namespace(&node));
|
||||||
|
}
|
||||||
|
{ // Logger name gets remapped
|
||||||
|
EXPECT_STREQ("original_ns.original_name", rcl_node_get_logger_name(&node));
|
||||||
|
}
|
||||||
|
{ // Publisher topic does not get remapped
|
||||||
|
const rosidl_message_type_support_t * ts = ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int64);
|
||||||
|
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||||
|
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||||
|
rcl_ret_t ret = rcl_publisher_init(&publisher, &node, ts, "/foo/bar", &publisher_options);
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/foo/bar", rcl_publisher_get_topic_name(&publisher));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_publisher_fini(&publisher, &node));
|
||||||
|
}
|
||||||
|
{ // Subscription topic does not get remapped
|
||||||
|
const rosidl_message_type_support_t * ts = ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int64);
|
||||||
|
rcl_subscription_options_t subscription_options = rcl_subscription_get_default_options();
|
||||||
|
rcl_subscription_t subscription = rcl_get_zero_initialized_subscription();
|
||||||
|
rcl_ret_t ret = rcl_subscription_init(
|
||||||
|
&subscription, &node, ts, "/foo/bar", &subscription_options);
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/foo/bar", rcl_subscription_get_topic_name(&subscription));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_subscription_fini(&subscription, &node));
|
||||||
|
}
|
||||||
|
{ // Client service name does not get remapped
|
||||||
|
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
|
||||||
|
example_interfaces, AddTwoInts);
|
||||||
|
rcl_client_options_t client_options = rcl_client_get_default_options();
|
||||||
|
rcl_client_t client = rcl_get_zero_initialized_client();
|
||||||
|
rcl_ret_t ret = rcl_client_init(&client, &node, ts, "/foo/bar", &client_options);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/foo/bar", rcl_client_get_service_name(&client));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_client_fini(&client, &node));
|
||||||
|
}
|
||||||
|
{ // Server service name does not get remapped
|
||||||
|
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
|
||||||
|
example_interfaces, AddTwoInts);
|
||||||
|
rcl_service_options_t service_options = rcl_service_get_default_options();
|
||||||
|
rcl_service_t service = rcl_get_zero_initialized_service();
|
||||||
|
rcl_ret_t ret = rcl_service_init(&service, &node, ts, "/foo/bar", &service_options);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/foo/bar", rcl_service_get_service_name(&service));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_service_fini(&service, &node));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_node_fini(&node));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapIntegrationFixture, RMW_IMPLEMENTATION), local_rules_before_global) {
|
||||||
|
int argc;
|
||||||
|
char ** argv;
|
||||||
|
SCOPE_GLOBAL_ARGS(
|
||||||
|
argc, argv, "process_name", "__node:=global_name", "__ns:=/global_ns", "/foo/bar:=/bar/global");
|
||||||
|
rcl_arguments_t local_arguments;
|
||||||
|
SCOPE_ARGS(
|
||||||
|
local_arguments,
|
||||||
|
"process_name", "__node:=local_name", "__ns:=/local_ns", "/foo/bar:=/bar/local");
|
||||||
|
|
||||||
|
rcl_node_t node = rcl_get_zero_initialized_node();
|
||||||
|
rcl_node_options_t options = rcl_node_get_default_options();
|
||||||
|
options.arguments = local_arguments;
|
||||||
|
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "/original_ns", &options));
|
||||||
|
|
||||||
|
{ // Node name
|
||||||
|
EXPECT_STREQ("local_name", rcl_node_get_name(&node));
|
||||||
|
}
|
||||||
|
{ // Node namespace
|
||||||
|
EXPECT_STREQ("/local_ns", rcl_node_get_namespace(&node));
|
||||||
|
}
|
||||||
|
{ // Logger name
|
||||||
|
EXPECT_STREQ("local_ns.local_name", rcl_node_get_logger_name(&node));
|
||||||
|
}
|
||||||
|
{ // Publisher topic
|
||||||
|
const rosidl_message_type_support_t * ts = ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int64);
|
||||||
|
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||||
|
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||||
|
rcl_ret_t ret = rcl_publisher_init(&publisher, &node, ts, "/foo/bar", &publisher_options);
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/bar/local", rcl_publisher_get_topic_name(&publisher));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_publisher_fini(&publisher, &node));
|
||||||
|
}
|
||||||
|
{ // Subscription topic
|
||||||
|
const rosidl_message_type_support_t * ts = ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int64);
|
||||||
|
rcl_subscription_options_t subscription_options = rcl_subscription_get_default_options();
|
||||||
|
rcl_subscription_t subscription = rcl_get_zero_initialized_subscription();
|
||||||
|
rcl_ret_t ret = rcl_subscription_init(
|
||||||
|
&subscription, &node, ts, "/foo/bar", &subscription_options);
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/bar/local", rcl_subscription_get_topic_name(&subscription));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_subscription_fini(&subscription, &node));
|
||||||
|
}
|
||||||
|
{ // Client service name
|
||||||
|
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
|
||||||
|
example_interfaces, AddTwoInts);
|
||||||
|
rcl_client_options_t client_options = rcl_client_get_default_options();
|
||||||
|
rcl_client_t client = rcl_get_zero_initialized_client();
|
||||||
|
rcl_ret_t ret = rcl_client_init(&client, &node, ts, "/foo/bar", &client_options);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/bar/local", rcl_client_get_service_name(&client));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_client_fini(&client, &node));
|
||||||
|
}
|
||||||
|
{ // Server service name
|
||||||
|
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
|
||||||
|
example_interfaces, AddTwoInts);
|
||||||
|
rcl_service_options_t service_options = rcl_service_get_default_options();
|
||||||
|
rcl_service_t service = rcl_get_zero_initialized_service();
|
||||||
|
rcl_ret_t ret = rcl_service_init(&service, &node, ts, "/foo/bar", &service_options);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/bar/local", rcl_service_get_service_name(&service));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_service_fini(&service, &node));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_node_fini(&node));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CLASSNAME(TestRemapIntegrationFixture, RMW_IMPLEMENTATION), remap_relative_topic) {
|
||||||
|
int argc;
|
||||||
|
char ** argv;
|
||||||
|
SCOPE_GLOBAL_ARGS(argc, argv, "process_name", "/foo/bar:=remap/global");
|
||||||
|
|
||||||
|
rcl_node_t node = rcl_get_zero_initialized_node();
|
||||||
|
rcl_node_options_t default_options = rcl_node_get_default_options();
|
||||||
|
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "/foo", &default_options));
|
||||||
|
|
||||||
|
{ // Publisher topic
|
||||||
|
const rosidl_message_type_support_t * ts = ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int64);
|
||||||
|
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||||
|
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||||
|
rcl_ret_t ret = rcl_publisher_init(&publisher, &node, ts, "bar", &publisher_options);
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/foo/remap/global", rcl_publisher_get_topic_name(&publisher));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_publisher_fini(&publisher, &node));
|
||||||
|
}
|
||||||
|
{ // Subscription topic
|
||||||
|
const rosidl_message_type_support_t * ts = ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int64);
|
||||||
|
rcl_subscription_options_t subscription_options = rcl_subscription_get_default_options();
|
||||||
|
rcl_subscription_t subscription = rcl_get_zero_initialized_subscription();
|
||||||
|
rcl_ret_t ret = rcl_subscription_init(
|
||||||
|
&subscription, &node, ts, "bar", &subscription_options);
|
||||||
|
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/foo/remap/global", rcl_subscription_get_topic_name(&subscription));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_subscription_fini(&subscription, &node));
|
||||||
|
}
|
||||||
|
{ // Client service name
|
||||||
|
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
|
||||||
|
example_interfaces, AddTwoInts);
|
||||||
|
rcl_client_options_t client_options = rcl_client_get_default_options();
|
||||||
|
rcl_client_t client = rcl_get_zero_initialized_client();
|
||||||
|
rcl_ret_t ret = rcl_client_init(&client, &node, ts, "bar", &client_options);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/foo/remap/global", rcl_client_get_service_name(&client));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_client_fini(&client, &node));
|
||||||
|
}
|
||||||
|
{ // Server service name
|
||||||
|
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
|
||||||
|
example_interfaces, AddTwoInts);
|
||||||
|
rcl_service_options_t service_options = rcl_service_get_default_options();
|
||||||
|
rcl_service_t service = rcl_get_zero_initialized_service();
|
||||||
|
rcl_ret_t ret = rcl_service_init(&service, &node, ts, "bar", &service_options);
|
||||||
|
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string_safe();
|
||||||
|
EXPECT_STREQ("/foo/remap/global", rcl_service_get_service_name(&service));
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_service_fini(&service, &node));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(RCL_RET_OK, rcl_node_fini(&node));
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue