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()
 | 
			
		||||
 | 
			
		||||
set(${PROJECT_NAME}_sources
 | 
			
		||||
  src/rcl/arguments.c
 | 
			
		||||
  src/rcl/client.c
 | 
			
		||||
  src/rcl/common.c
 | 
			
		||||
  src/rcl/expand_topic_name.c
 | 
			
		||||
| 
						 | 
				
			
			@ -35,6 +36,7 @@ set(${PROJECT_NAME}_sources
 | 
			
		|||
  src/rcl/node.c
 | 
			
		||||
  src/rcl/publisher.c
 | 
			
		||||
  src/rcl/rcl.c
 | 
			
		||||
  src/rcl/remap.c
 | 
			
		||||
  src/rcl/rmw_implementation_identifier_check.c
 | 
			
		||||
  src/rcl/service.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 "rcl/allocator.h"
 | 
			
		||||
#include "rcl/arguments.h"
 | 
			
		||||
#include "rcl/macros.h"
 | 
			
		||||
#include "rcl/types.h"
 | 
			
		||||
#include "rcl/visibility_control.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -65,6 +66,12 @@ typedef struct rcl_node_options_t
 | 
			
		|||
 | 
			
		||||
  /// Custom allocator used for internal allocations.
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
/// 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.
 | 
			
		||||
#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_
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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/expand_topic_name.h"
 | 
			
		||||
#include "rcl/remap.h"
 | 
			
		||||
#include "rcutils/logging_macros.h"
 | 
			
		||||
#include "rmw/error_handling.h"
 | 
			
		||||
#include "rmw/rmw.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -100,6 +101,7 @@ rcl_client_init(
 | 
			
		|||
    return RCL_RET_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
  char * expanded_service_name = NULL;
 | 
			
		||||
  char * remapped_service_name = NULL;
 | 
			
		||||
  ret = rcl_expand_topic_name(
 | 
			
		||||
    service_name,
 | 
			
		||||
    rcl_node_get_name(node),
 | 
			
		||||
| 
						 | 
				
			
			@ -114,40 +116,60 @@ rcl_client_init(
 | 
			
		|||
    return RCL_RET_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
  if (ret != RCL_RET_OK) {
 | 
			
		||||
    if (ret == RCL_RET_BAD_ALLOC) {
 | 
			
		||||
      return ret;
 | 
			
		||||
    } else if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
 | 
			
		||||
      return RCL_RET_SERVICE_NAME_INVALID;
 | 
			
		||||
    if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
 | 
			
		||||
      ret = RCL_RET_SERVICE_NAME_INVALID;
 | 
			
		||||
    } 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)
 | 
			
		||||
 | 
			
		||||
  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.
 | 
			
		||||
  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) {
 | 
			
		||||
    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) {
 | 
			
		||||
    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.
 | 
			
		||||
  client->impl = (rcl_client_impl_t *)allocator->allocate(
 | 
			
		||||
    sizeof(rcl_client_impl_t), allocator->state);
 | 
			
		||||
  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.
 | 
			
		||||
  // rmw handle (create rmw client)
 | 
			
		||||
  // TODO(wjwwood): pass along the allocator to rmw when it supports it
 | 
			
		||||
  client->impl->rmw_handle = rmw_create_client(
 | 
			
		||||
    rcl_node_get_rmw_handle(node),
 | 
			
		||||
    type_support,
 | 
			
		||||
    expanded_service_name,
 | 
			
		||||
    remapped_service_name,
 | 
			
		||||
    &options->qos);
 | 
			
		||||
  allocator->deallocate(expanded_service_name, allocator->state);
 | 
			
		||||
  if (!client->impl->rmw_handle) {
 | 
			
		||||
    RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
 | 
			
		||||
    goto fail;
 | 
			
		||||
| 
						 | 
				
			
			@ -155,12 +177,22 @@ rcl_client_init(
 | 
			
		|||
  // options
 | 
			
		||||
  client->impl->options = *options;
 | 
			
		||||
  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Client initialized")
 | 
			
		||||
  return RCL_RET_OK;
 | 
			
		||||
  ret = RCL_RET_OK;
 | 
			
		||||
  goto cleanup;
 | 
			
		||||
fail:
 | 
			
		||||
  if (client->impl) {
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,8 +24,10 @@ extern "C"
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "rcl/arguments.h"
 | 
			
		||||
#include "rcl/error_handling.h"
 | 
			
		||||
#include "rcl/rcl.h"
 | 
			
		||||
#include "rcl/remap.h"
 | 
			
		||||
#include "rcutils/filesystem.h"
 | 
			
		||||
#include "rcutils/find.h"
 | 
			
		||||
#include "rcutils/format_string.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -142,6 +144,7 @@ rcl_node_init(
 | 
			
		|||
    rcl_guard_condition_get_default_options();
 | 
			
		||||
  rcl_ret_t ret;
 | 
			
		||||
  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.
 | 
			
		||||
  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
 | 
			
		||||
    char * temp = (char *)allocator->allocate(namespace_length + 2, allocator->state);
 | 
			
		||||
    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] = '/';
 | 
			
		||||
    memcpy(temp + 1, namespace_, strlen(namespace_) + 1);
 | 
			
		||||
    local_namespace_ = temp;
 | 
			
		||||
| 
						 | 
				
			
			@ -202,34 +205,54 @@ rcl_node_init(
 | 
			
		|||
  ret = rmw_validate_namespace(local_namespace_, &validation_result, NULL);
 | 
			
		||||
  if (ret != RMW_RET_OK) {
 | 
			
		||||
    RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
 | 
			
		||||
    if (should_free_local_namespace_) {
 | 
			
		||||
      allocator->deallocate((char *)local_namespace_, allocator->state);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
    goto cleanup;
 | 
			
		||||
  }
 | 
			
		||||
  if (validation_result != RMW_NAMESPACE_VALID) {
 | 
			
		||||
    const char * msg = rmw_namespace_validation_result_string(validation_result);
 | 
			
		||||
    RCL_SET_ERROR_MSG_WITH_FORMAT_STRING((*allocator), "%s, result: %d", msg, validation_result);
 | 
			
		||||
 | 
			
		||||
    if (should_free_local_namespace_) {
 | 
			
		||||
      allocator->deallocate((char *)local_namespace_, allocator->state);
 | 
			
		||||
    }
 | 
			
		||||
    return RCL_RET_NODE_INVALID_NAMESPACE;
 | 
			
		||||
    ret = RCL_RET_NODE_INVALID_NAMESPACE;
 | 
			
		||||
    goto cleanup;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Allocate space for the implementation struct.
 | 
			
		||||
  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(
 | 
			
		||||
    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->graph_guard_condition = NULL;
 | 
			
		||||
  node->impl->logger_name = NULL;
 | 
			
		||||
  // Initialize node impl.
 | 
			
		||||
  // node options (assume it is trivially copyable)
 | 
			
		||||
  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->impl->logger_name = rcl_create_node_logger_name(name, local_namespace_, allocator);
 | 
			
		||||
  RCL_CHECK_FOR_NULL_WITH_MSG(
 | 
			
		||||
| 
						 | 
				
			
			@ -264,10 +287,8 @@ rcl_node_init(
 | 
			
		|||
    RCL_SET_ERROR_MSG(
 | 
			
		||||
      "Environment variable " RCUTILS_STRINGIFY(ROS_SECURITY_ENABLE_VAR_NAME)
 | 
			
		||||
      " could not be read", rcl_get_default_allocator());
 | 
			
		||||
    if (should_free_local_namespace_) {
 | 
			
		||||
      allocator->deallocate((char *)local_namespace_, allocator->state);
 | 
			
		||||
    }
 | 
			
		||||
    return RCL_RET_ERROR;
 | 
			
		||||
    ret = RCL_RET_ERROR;
 | 
			
		||||
    goto fail;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool use_security = (0 == strcmp(ros_security_enable, "true"));
 | 
			
		||||
| 
						 | 
				
			
			@ -278,10 +299,8 @@ rcl_node_init(
 | 
			
		|||
    RCL_SET_ERROR_MSG(
 | 
			
		||||
      "Environment variable " RCUTILS_STRINGIFY(ROS_SECURITY_STRATEGY_VAR_NAME)
 | 
			
		||||
      " could not be read", rcl_get_default_allocator());
 | 
			
		||||
    if (should_free_local_namespace_) {
 | 
			
		||||
      allocator->deallocate((char *)local_namespace_, allocator->state);
 | 
			
		||||
    }
 | 
			
		||||
    return RCL_RET_ERROR;
 | 
			
		||||
    ret = RCL_RET_ERROR;
 | 
			
		||||
    goto fail;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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 "
 | 
			
		||||
          RCUTILS_STRINGIFY(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME)
 | 
			
		||||
          " directory while the requested security strategy requires it", *allocator);
 | 
			
		||||
        if (should_free_local_namespace_) {
 | 
			
		||||
          allocator->deallocate((char *)local_namespace_, allocator->state);
 | 
			
		||||
        }
 | 
			
		||||
        return RCL_RET_ERROR;
 | 
			
		||||
        ret = RCL_RET_ERROR;
 | 
			
		||||
        goto cleanup;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -314,11 +331,6 @@ rcl_node_init(
 | 
			
		|||
 | 
			
		||||
  RCL_CHECK_FOR_NULL_WITH_MSG(
 | 
			
		||||
    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
 | 
			
		||||
  node->impl->rcl_instance_id = rcl_get_instance_id();
 | 
			
		||||
  // graph guard condition
 | 
			
		||||
| 
						 | 
				
			
			@ -345,7 +357,8 @@ rcl_node_init(
 | 
			
		|||
    goto fail;
 | 
			
		||||
  }
 | 
			
		||||
  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Node initialized")
 | 
			
		||||
  return RCL_RET_OK;
 | 
			
		||||
  ret = RCL_RET_OK;
 | 
			
		||||
  goto cleanup;
 | 
			
		||||
fail:
 | 
			
		||||
  if (node->impl) {
 | 
			
		||||
    if (node->impl->logger_name) {
 | 
			
		||||
| 
						 | 
				
			
			@ -374,11 +387,17 @@ fail:
 | 
			
		|||
  }
 | 
			
		||||
  *node = rcl_get_zero_initialized_node();
 | 
			
		||||
 | 
			
		||||
  ret = fail_ret;
 | 
			
		||||
  // fall through from fail -> cleanup
 | 
			
		||||
cleanup:
 | 
			
		||||
  if (should_free_local_namespace_) {
 | 
			
		||||
    allocator->deallocate((char *)local_namespace_, allocator->state);
 | 
			
		||||
    local_namespace_ = NULL;
 | 
			
		||||
  }
 | 
			
		||||
  return fail_ret;
 | 
			
		||||
  if (NULL != remapped_node_name) {
 | 
			
		||||
    allocator->deallocate(remapped_node_name, allocator->state);
 | 
			
		||||
  }
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
  static rcl_node_options_t default_options = {
 | 
			
		||||
    .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.
 | 
			
		||||
  default_options.allocator = rcl_get_default_allocator();
 | 
			
		||||
  default_options.arguments = rcl_get_zero_initialized_arguments();
 | 
			
		||||
  return default_options;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,7 @@ extern "C"
 | 
			
		|||
#include "rcl/allocator.h"
 | 
			
		||||
#include "rcl/error_handling.h"
 | 
			
		||||
#include "rcl/expand_topic_name.h"
 | 
			
		||||
#include "rcl/remap.h"
 | 
			
		||||
#include "rcutils/logging_macros.h"
 | 
			
		||||
#include "rmw/error_handling.h"
 | 
			
		||||
#include "rmw/rmw.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -99,6 +100,7 @@ rcl_publisher_init(
 | 
			
		|||
    return RCL_RET_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
  char * expanded_topic_name = NULL;
 | 
			
		||||
  char * remapped_topic_name = NULL;
 | 
			
		||||
  ret = rcl_expand_topic_name(
 | 
			
		||||
    topic_name,
 | 
			
		||||
    rcl_node_get_name(node),
 | 
			
		||||
| 
						 | 
				
			
			@ -108,56 +110,85 @@ rcl_publisher_init(
 | 
			
		|||
    &expanded_topic_name);
 | 
			
		||||
  rcutils_ret = rcutils_string_map_fini(&substitutions_map);
 | 
			
		||||
  if (rcutils_ret != RCUTILS_RET_OK) {
 | 
			
		||||
    RCL_SET_ERROR_MSG(rcutils_get_error_string_safe(), *allocator)
 | 
			
		||||
    allocator->deallocate(expanded_topic_name, allocator->state);
 | 
			
		||||
    return RCL_RET_ERROR;
 | 
			
		||||
    RCL_SET_ERROR_MSG(rcutils_get_error_string_safe(), *allocator);
 | 
			
		||||
    ret = RCL_RET_ERROR;
 | 
			
		||||
    goto cleanup;
 | 
			
		||||
  }
 | 
			
		||||
  if (ret != RCL_RET_OK) {
 | 
			
		||||
    if (ret == RCL_RET_BAD_ALLOC) {
 | 
			
		||||
      return ret;
 | 
			
		||||
    } else if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
 | 
			
		||||
      return RCL_RET_TOPIC_NAME_INVALID;
 | 
			
		||||
    if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
 | 
			
		||||
      ret = RCL_RET_TOPIC_NAME_INVALID;
 | 
			
		||||
    } 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)
 | 
			
		||||
 | 
			
		||||
  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.
 | 
			
		||||
  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) {
 | 
			
		||||
    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) {
 | 
			
		||||
    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.
 | 
			
		||||
  publisher->impl = (rcl_publisher_impl_t *)allocator->allocate(
 | 
			
		||||
    sizeof(rcl_publisher_impl_t), allocator->state);
 | 
			
		||||
  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.
 | 
			
		||||
  // rmw handle (create rmw publisher)
 | 
			
		||||
  // TODO(wjwwood): pass along the allocator to rmw when it supports it
 | 
			
		||||
  publisher->impl->rmw_handle = rmw_create_publisher(
 | 
			
		||||
    rcl_node_get_rmw_handle(node),
 | 
			
		||||
    type_support,
 | 
			
		||||
    expanded_topic_name,
 | 
			
		||||
    remapped_topic_name,
 | 
			
		||||
    &(options->qos));
 | 
			
		||||
  allocator->deallocate(expanded_topic_name, allocator->state);
 | 
			
		||||
  RCL_CHECK_FOR_NULL_WITH_MSG(publisher->impl->rmw_handle,
 | 
			
		||||
    rmw_get_error_string_safe(), goto fail, *allocator);
 | 
			
		||||
  // options
 | 
			
		||||
  publisher->impl->options = *options;
 | 
			
		||||
  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Publisher initialized")
 | 
			
		||||
  return RCL_RET_OK;
 | 
			
		||||
  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Publisher initialized");
 | 
			
		||||
  goto cleanup;
 | 
			
		||||
fail:
 | 
			
		||||
  if (publisher->impl) {
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,9 @@ extern "C"
 | 
			
		|||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "./arguments_impl.h"
 | 
			
		||||
#include "./stdatomic_helper.h"
 | 
			
		||||
#include "rcl/arguments.h"
 | 
			
		||||
#include "rcl/error_handling.h"
 | 
			
		||||
#include "rcutils/logging_macros.h"
 | 
			
		||||
#include "rmw/error_handling.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +51,11 @@ __clean_up_init()
 | 
			
		|||
  }
 | 
			
		||||
  __rcl_argc = 0;
 | 
			
		||||
  __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_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);
 | 
			
		||||
    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,
 | 
			
		||||
  // 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...
 | 
			
		||||
| 
						 | 
				
			
			@ -101,6 +113,10 @@ rcl_init(int argc, char ** argv, rcl_allocator_t allocator)
 | 
			
		|||
    }
 | 
			
		||||
    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);
 | 
			
		||||
  if (rcl_atomic_load_uint64_t(&__rcl_instance_id) == 0) {
 | 
			
		||||
    // 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/expand_topic_name.h"
 | 
			
		||||
#include "rcl/remap.h"
 | 
			
		||||
#include "rcutils/logging_macros.h"
 | 
			
		||||
#include "rmw/error_handling.h"
 | 
			
		||||
#include "rmw/rmw.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -97,6 +98,7 @@ rcl_service_init(
 | 
			
		|||
    return RCL_RET_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
  char * expanded_service_name = NULL;
 | 
			
		||||
  char * remapped_service_name = NULL;
 | 
			
		||||
  ret = rcl_expand_topic_name(
 | 
			
		||||
    service_name,
 | 
			
		||||
    rcl_node_get_name(node),
 | 
			
		||||
| 
						 | 
				
			
			@ -107,35 +109,57 @@ rcl_service_init(
 | 
			
		|||
  rcutils_ret = rcutils_string_map_fini(&substitutions_map);
 | 
			
		||||
  if (rcutils_ret != RCUTILS_RET_OK) {
 | 
			
		||||
    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;
 | 
			
		||||
  }
 | 
			
		||||
  if (ret != RCL_RET_OK) {
 | 
			
		||||
    if (ret == RCL_RET_BAD_ALLOC) {
 | 
			
		||||
      return ret;
 | 
			
		||||
    } else if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
 | 
			
		||||
      return RCL_RET_SERVICE_NAME_INVALID;
 | 
			
		||||
    if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
 | 
			
		||||
      ret = RCL_RET_SERVICE_NAME_INVALID;
 | 
			
		||||
    } 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)
 | 
			
		||||
 | 
			
		||||
  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.
 | 
			
		||||
  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) {
 | 
			
		||||
    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) {
 | 
			
		||||
    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.
 | 
			
		||||
  service->impl = (rcl_service_impl_t *)allocator->allocate(
 | 
			
		||||
    sizeof(rcl_service_impl_t), allocator->state);
 | 
			
		||||
  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) {
 | 
			
		||||
    RCUTILS_LOG_WARN_NAMED(
 | 
			
		||||
| 
						 | 
				
			
			@ -149,9 +173,8 @@ rcl_service_init(
 | 
			
		|||
  service->impl->rmw_handle = rmw_create_service(
 | 
			
		||||
    rcl_node_get_rmw_handle(node),
 | 
			
		||||
    type_support,
 | 
			
		||||
    expanded_service_name,
 | 
			
		||||
    remapped_service_name,
 | 
			
		||||
    &options->qos);
 | 
			
		||||
  allocator->deallocate(expanded_service_name, allocator->state);
 | 
			
		||||
  if (!service->impl->rmw_handle) {
 | 
			
		||||
    RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
 | 
			
		||||
    goto fail;
 | 
			
		||||
| 
						 | 
				
			
			@ -159,12 +182,22 @@ rcl_service_init(
 | 
			
		|||
  // options
 | 
			
		||||
  service->impl->options = *options;
 | 
			
		||||
  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Service initialized")
 | 
			
		||||
  return RCL_RET_OK;
 | 
			
		||||
  ret = RCL_RET_OK;
 | 
			
		||||
  goto cleanup;
 | 
			
		||||
fail:
 | 
			
		||||
  if (service->impl) {
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ extern "C"
 | 
			
		|||
 | 
			
		||||
#include "rcl/error_handling.h"
 | 
			
		||||
#include "rcl/expand_topic_name.h"
 | 
			
		||||
#include "rcl/remap.h"
 | 
			
		||||
#include "rcutils/logging_macros.h"
 | 
			
		||||
#include "rmw/error_handling.h"
 | 
			
		||||
#include "rmw/rmw.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -96,6 +97,7 @@ rcl_subscription_init(
 | 
			
		|||
    return RCL_RET_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
  char * expanded_topic_name = NULL;
 | 
			
		||||
  char * remapped_topic_name = NULL;
 | 
			
		||||
  ret = rcl_expand_topic_name(
 | 
			
		||||
    topic_name,
 | 
			
		||||
    rcl_node_get_name(node),
 | 
			
		||||
| 
						 | 
				
			
			@ -106,45 +108,66 @@ rcl_subscription_init(
 | 
			
		|||
  rcutils_ret = rcutils_string_map_fini(&substitutions_map);
 | 
			
		||||
  if (rcutils_ret != RCUTILS_RET_OK) {
 | 
			
		||||
    RCL_SET_ERROR_MSG(rcutils_get_error_string_safe(), *allocator)
 | 
			
		||||
    allocator->deallocate(expanded_topic_name, allocator->state);
 | 
			
		||||
    return RCL_RET_ERROR;
 | 
			
		||||
    ret = RCL_RET_ERROR;
 | 
			
		||||
    goto cleanup;
 | 
			
		||||
  }
 | 
			
		||||
  if (ret != RCL_RET_OK) {
 | 
			
		||||
    if (ret == RCL_RET_BAD_ALLOC) {
 | 
			
		||||
      return ret;
 | 
			
		||||
    } else if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
 | 
			
		||||
      return RCL_RET_TOPIC_NAME_INVALID;
 | 
			
		||||
    if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
 | 
			
		||||
      ret = RCL_RET_TOPIC_NAME_INVALID;
 | 
			
		||||
    } 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)
 | 
			
		||||
 | 
			
		||||
  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.
 | 
			
		||||
  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) {
 | 
			
		||||
    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) {
 | 
			
		||||
    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.
 | 
			
		||||
  subscription->impl = (rcl_subscription_impl_t *)allocator->allocate(
 | 
			
		||||
    sizeof(rcl_subscription_impl_t), allocator->state);
 | 
			
		||||
  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.
 | 
			
		||||
  // rmw_handle
 | 
			
		||||
  // TODO(wjwwood): pass allocator once supported in rmw api.
 | 
			
		||||
  subscription->impl->rmw_handle = rmw_create_subscription(
 | 
			
		||||
    rcl_node_get_rmw_handle(node),
 | 
			
		||||
    type_support,
 | 
			
		||||
    expanded_topic_name,
 | 
			
		||||
    remapped_topic_name,
 | 
			
		||||
    &(options->qos),
 | 
			
		||||
    options->ignore_local_publications);
 | 
			
		||||
  allocator->deallocate(expanded_topic_name, allocator->state);
 | 
			
		||||
  if (!subscription->impl->rmw_handle) {
 | 
			
		||||
    RCL_SET_ERROR_MSG(rmw_get_error_string_safe(), *allocator);
 | 
			
		||||
    goto fail;
 | 
			
		||||
| 
						 | 
				
			
			@ -152,12 +175,22 @@ rcl_subscription_init(
 | 
			
		|||
  // options
 | 
			
		||||
  subscription->impl->options = *options;
 | 
			
		||||
  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Subscription initialized")
 | 
			
		||||
  return RCL_RET_OK;
 | 
			
		||||
  ret = RCL_RET_OK;
 | 
			
		||||
  goto cleanup;
 | 
			
		||||
fail:
 | 
			
		||||
  if (subscription->impl) {
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,6 +100,29 @@ function(test_target_function)
 | 
			
		|||
    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}
 | 
			
		||||
    SRCS rcl/test_guard_condition.cpp
 | 
			
		||||
    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