From b8159b6dbe14a919da8a468bd90a7a759624ccc4 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Thu, 2 May 2019 23:17:44 +0000 Subject: [PATCH 01/10] Add in cross-platform rcutils method to get home directory. Signed-off-by: Chris Lalancette --- include/rcutils/get_env.h | 24 ++++++++++++++++++++++++ src/get_env.c | 21 +++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/include/rcutils/get_env.h b/include/rcutils/get_env.h index 29e85584..89b1dcb4 100644 --- a/include/rcutils/get_env.h +++ b/include/rcutils/get_env.h @@ -61,6 +61,30 @@ RCUTILS_WARN_UNUSED const char * rcutils_get_env(const char * env_name, const char ** env_value); +// Retrieve the full path to the home directory. +/* + * The c-string which is returned is only valid until the next time this + * function is called, because it is a direct pointer to the static storage. + * Also note that the string returned here should *not* be freed. + * + * The function work by first trying to get the contents of the HOME environment + * variable. If that variable exists and is non-empty, that will be returned. + * Otherwise, the function will try to get the contents of the USERPROFILE + * environment variable. If that variable exists and is non-empty, that will be + * returned. If neither exists, NULL will be returned. The above algorithm + * should be portable across both Unix and Windows. + * + * The home directory will be truncated at 2048 characters on Windows. + * + * This function is not thread-safe. + * + * \return The home directory on success, NULL on failure. + */ +RCUTILS_PUBLIC +RCUTILS_WARN_UNUSED +const char * +rcutils_get_home_dir(void); + #ifdef __cplusplus } #endif diff --git a/src/get_env.c b/src/get_env.c index 3fdff69f..3821ee0b 100644 --- a/src/get_env.c +++ b/src/get_env.c @@ -55,6 +55,27 @@ rcutils_get_env(const char * env_name, const char ** env_value) return NULL; } +const char * +rcutils_get_home_dir(void) +{ + const char * homedir; + + if (rcutils_get_env("HOME", &homedir) == NULL && *homedir != '\0') { + // The HOME environment variable was set and is non-empty, return it. + return homedir; + } + + // OK, we didn't find a HOME variable, try USERPROFILE (mostly for + // Windows) + if (rcutils_get_env("USERPROFILE", &homedir) == NULL && *homedir != '\0') { + // The USERPROFILE environment variable was set and is non-empty, return it. + return homedir; + } + + // Couldn't get the home directory, return NULL. + return NULL; +} + #ifdef __cplusplus } #endif From 0adb3ae797a682d441a23c03fae988838d53e974 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Thu, 2 May 2019 23:25:20 +0000 Subject: [PATCH 02/10] Add cross-platform way to get the PID and program name. Signed-off-by: Chris Lalancette --- CMakeLists.txt | 1 + include/rcutils/program.h | 57 +++++++++++++++++++++++++++++ src/program.c | 77 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 include/rcutils/program.h create mode 100644 src/program.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1de77ae1..213ec475 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ set(rcutils_sources src/get_env.c src/hash_map.c src/logging.c + src/program.c src/repl_str.c src/snprintf.c src/split.c diff --git a/include/rcutils/program.h b/include/rcutils/program.h new file mode 100644 index 00000000..bf0c4d88 --- /dev/null +++ b/include/rcutils/program.h @@ -0,0 +1,57 @@ +// Copyright 2019 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 RCUTILS__PROGRAM_H_ +#define RCUTILS__PROGRAM_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "rcutils/allocator.h" +#include "rcutils/macros.h" +#include "rcutils/visibility_control.h" + +// Retrieve the current process ID. +/* + * This function returns the current process ID, and is always successful. + * + * This function is thread-safe. + * + * \return The current process ID. + */ +RCUTILS_PUBLIC +RCUTILS_WARN_UNUSED +int rcutils_get_pid(void); + +// Retrieve the current program name. +/* + * This function portably retrieves the current program name and returns + * a copy of it. It is up to the caller to free the memory. + * + * This function is thread-safe. + * + * \param[in] allocator the allocator to use + * \return The program name on success, NULL on failure. + */ +RCUTILS_PUBLIC +RCUTILS_WARN_UNUSED +char * rcutils_get_program_name(rcutils_allocator_t allocator); + +#ifdef __cplusplus +} +#endif + +#endif // RCUTILS__PROGRAM_H_ diff --git a/src/program.c b/src/program.c new file mode 100644 index 00000000..c3e98ffc --- /dev/null +++ b/src/program.c @@ -0,0 +1,77 @@ +// Copyright 2019 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. + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define _GNU_SOURCE +#include +#include +#include + +#if defined _WIN32 || defined __CYGWIN__ +#include +#else +#include +#endif + +#include "rcutils/allocator.h" +#include "rcutils/error_handling.h" + +int rcutils_get_pid(void) +{ +#if defined _WIN32 || defined __CYGWIN__ + return (int)GetCurrentProcessId(); +#else + return (int)getpid(); +#endif +} + +char *rcutils_get_program_name(rcutils_allocator_t allocator) +{ + RCUTILS_CHECK_ALLOCATOR_WITH_MSG( + &allocator, "invalid allocator", return NULL); + +#if defined __APPLE__ + const char * appname = getprogname(); +#elif defined __GNUC__ + const char * appname = program_invocation_name; +#elif defined _WIN32 || defined __CYGWIN + int32_t size; + const char appname[MAX_PATH]; + size = GetModuleFileNameA(NULL, appname, MAX_PATH); + // TODO(clalancette): deal with error +#else +#error "Unsupported OS" +#endif + + size_t len = strlen(appname); + + // Since the above memory may be static, and the caller may want to modify + // the argument, make and return a copy here. + char * basec = allocator.allocate(len + 1, allocator.state); + if (NULL == basec) { + return NULL; + } + memcpy(basec, appname, len); + basec[len] = '\0'; + + return basec; +} + +#ifdef __cplusplus +} +#endif From 736be92a04d17244ac04f8b461db3cc7d0b870b5 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 3 May 2019 19:28:41 +0000 Subject: [PATCH 03/10] Move basename fetching into rcutils_get_program_name. That way it is easier to use from the outside. Signed-off-by: Chris Lalancette --- src/program.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/program.c b/src/program.c index c3e98ffc..ce145713 100644 --- a/src/program.c +++ b/src/program.c @@ -50,24 +50,48 @@ char *rcutils_get_program_name(rcutils_allocator_t allocator) #elif defined __GNUC__ const char * appname = program_invocation_name; #elif defined _WIN32 || defined __CYGWIN - int32_t size; const char appname[MAX_PATH]; - size = GetModuleFileNameA(NULL, appname, MAX_PATH); - // TODO(clalancette): deal with error + int32_t size = GetModuleFileNameA(NULL, appname, MAX_PATH); + if (size == 0) { + return NULL; + } #else #error "Unsupported OS" #endif - size_t len = strlen(appname); + size_t applen = strlen(appname); // Since the above memory may be static, and the caller may want to modify // the argument, make and return a copy here. - char * basec = allocator.allocate(len + 1, allocator.state); + char * basec = allocator.allocate(applen + 1, allocator.state); if (NULL == basec) { return NULL; } - memcpy(basec, appname, len); - basec[len] = '\0'; + + // Get just the executable name (Unix may return the absolute path) +#if defined __APPLE__ || defined __GNUC__ + // We need an intermediate copy because basename may modify its arguments + char * intermediate = allocator.allocate(applen + 1, allocator.state); + if (NULL == intermediate) { + return NULL; + } + memcpy(intermediate, appname, applen); + intermediate[applen] = '\0'; + + char * bname = basename(intermediate); + size_t baselen = strlen(bname); + memcpy(basec, bname, baselen); + basec[baselen] = '\0'; + allocator.deallocate(intermediate, allocator.state); +#elif defined _WIN32 || defined __CYGWIN + errno_t err = _splitpath_s(appname, NULL, 0, NULL, 0, basec, applen, NULL, 0); + if (err != 0) { + allocator.deallocate(basec, allocator.state); + return NULL; + } +#else +#error "Unsupported OS" +#endif return basec; } From de1bbc33a1715f53aa1b6f23d25b8e468d24ce09 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 3 May 2019 21:45:14 +0000 Subject: [PATCH 04/10] Review feedback. Signed-off-by: Chris Lalancette --- include/rcutils/get_env.h | 14 +++++++------- include/rcutils/program.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/rcutils/get_env.h b/include/rcutils/get_env.h index 89b1dcb4..787e6089 100644 --- a/include/rcutils/get_env.h +++ b/include/rcutils/get_env.h @@ -61,18 +61,18 @@ RCUTILS_WARN_UNUSED const char * rcutils_get_env(const char * env_name, const char ** env_value); -// Retrieve the full path to the home directory. +/// Retrieve the full path to the home directory. /* * The c-string which is returned is only valid until the next time this * function is called, because it is a direct pointer to the static storage. * Also note that the string returned here should *not* be freed. * - * The function work by first trying to get the contents of the HOME environment - * variable. If that variable exists and is non-empty, that will be returned. - * Otherwise, the function will try to get the contents of the USERPROFILE - * environment variable. If that variable exists and is non-empty, that will be - * returned. If neither exists, NULL will be returned. The above algorithm - * should be portable across both Unix and Windows. + * The function first tries to get the HOME environment variable. + * If that variable exists and is non-empty, that will be returned. + * Otherwise, the function tries to get the USERPROFILE environment variable. + * If that variable exists and is non-empty, that will be returned. + * If neither exists, NULL will be returned. + * The above algorithm is portable across both Unix and Windows. * * The home directory will be truncated at 2048 characters on Windows. * diff --git a/include/rcutils/program.h b/include/rcutils/program.h index bf0c4d88..21d15da5 100644 --- a/include/rcutils/program.h +++ b/include/rcutils/program.h @@ -24,7 +24,7 @@ extern "C" #include "rcutils/macros.h" #include "rcutils/visibility_control.h" -// Retrieve the current process ID. +/// Retrieve the current process ID. /* * This function returns the current process ID, and is always successful. * @@ -36,7 +36,7 @@ RCUTILS_PUBLIC RCUTILS_WARN_UNUSED int rcutils_get_pid(void); -// Retrieve the current program name. +/// Retrieve the current program name. /* * This function portably retrieves the current program name and returns * a copy of it. It is up to the caller to free the memory. From cc25d97be662e7e6ae212ed958a2f7d2fbb74efa Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 3 May 2019 21:50:31 +0000 Subject: [PATCH 05/10] Review fixes. Signed-off-by: Chris Lalancette --- CMakeLists.txt | 2 +- include/rcutils/{program.h => process.h} | 7 ++++--- src/{program.c => process.c} | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) rename include/rcutils/{program.h => process.h} (88%) rename src/{program.c => process.c} (95%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 213ec475..58b1cf41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ set(rcutils_sources src/get_env.c src/hash_map.c src/logging.c - src/program.c + src/process.c src/repl_str.c src/snprintf.c src/split.c diff --git a/include/rcutils/program.h b/include/rcutils/process.h similarity index 88% rename from include/rcutils/program.h rename to include/rcutils/process.h index 21d15da5..83f99dfa 100644 --- a/include/rcutils/program.h +++ b/include/rcutils/process.h @@ -36,10 +36,11 @@ RCUTILS_PUBLIC RCUTILS_WARN_UNUSED int rcutils_get_pid(void); -/// Retrieve the current program name. +/// Retrieve the current executable name. /* * This function portably retrieves the current program name and returns - * a copy of it. It is up to the caller to free the memory. + * a copy of it. + * It is up to the caller to free the memory. * * This function is thread-safe. * @@ -48,7 +49,7 @@ int rcutils_get_pid(void); */ RCUTILS_PUBLIC RCUTILS_WARN_UNUSED -char * rcutils_get_program_name(rcutils_allocator_t allocator); +char * rcutils_get_executable_name(rcutils_allocator_t allocator); #ifdef __cplusplus } diff --git a/src/program.c b/src/process.c similarity index 95% rename from src/program.c rename to src/process.c index ce145713..f1ae92b6 100644 --- a/src/program.c +++ b/src/process.c @@ -40,7 +40,7 @@ int rcutils_get_pid(void) #endif } -char *rcutils_get_program_name(rcutils_allocator_t allocator) +char * rcutils_get_executable_name(rcutils_allocator_t allocator) { RCUTILS_CHECK_ALLOCATOR_WITH_MSG( &allocator, "invalid allocator", return NULL); @@ -73,6 +73,7 @@ char *rcutils_get_program_name(rcutils_allocator_t allocator) // We need an intermediate copy because basename may modify its arguments char * intermediate = allocator.allocate(applen + 1, allocator.state); if (NULL == intermediate) { + allocator.deallocate(basec, allocator.state); return NULL; } memcpy(intermediate, appname, applen); From ffa6b4251dec1909092b13aa7251b6e26f44f3cb Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 3 May 2019 23:02:32 +0000 Subject: [PATCH 06/10] Fix include guards. Signed-off-by: Chris Lalancette --- include/rcutils/process.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/rcutils/process.h b/include/rcutils/process.h index 83f99dfa..2caf45bb 100644 --- a/include/rcutils/process.h +++ b/include/rcutils/process.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef RCUTILS__PROGRAM_H_ -#define RCUTILS__PROGRAM_H_ +#ifndef RCUTILS__PROCESS_H_ +#define RCUTILS__PROCESS_H_ #ifdef __cplusplus extern "C" @@ -55,4 +55,4 @@ char * rcutils_get_executable_name(rcutils_allocator_t allocator); } #endif -#endif // RCUTILS__PROGRAM_H_ +#endif // RCUTILS__PROCESS_H_ From e9a416745068b4ccdbde6ae377edd14eca45ae64 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 3 May 2019 23:29:01 +0000 Subject: [PATCH 07/10] Fixes for Windows. Signed-off-by: Chris Lalancette --- src/process.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/process.c b/src/process.c index f1ae92b6..89b6710c 100644 --- a/src/process.c +++ b/src/process.c @@ -30,6 +30,7 @@ extern "C" #include "rcutils/allocator.h" #include "rcutils/error_handling.h" +#include "rcutils/process.h" int rcutils_get_pid(void) { @@ -50,7 +51,7 @@ char * rcutils_get_executable_name(rcutils_allocator_t allocator) #elif defined __GNUC__ const char * appname = program_invocation_name; #elif defined _WIN32 || defined __CYGWIN - const char appname[MAX_PATH]; + char appname[MAX_PATH]; int32_t size = GetModuleFileNameA(NULL, appname, MAX_PATH); if (size == 0) { return NULL; From 3352d19b166f16c7e0c2cd091a2b464dfccd4605 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Sat, 4 May 2019 00:09:12 +0000 Subject: [PATCH 08/10] Wrap check for USERPROFILE in _WIN32. Signed-off-by: Chris Lalancette --- src/get_env.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/get_env.c b/src/get_env.c index 3821ee0b..c9370722 100644 --- a/src/get_env.c +++ b/src/get_env.c @@ -65,12 +65,13 @@ rcutils_get_home_dir(void) return homedir; } - // OK, we didn't find a HOME variable, try USERPROFILE (mostly for - // Windows) +#ifdef _WIN32 + // We didn't find a HOME variable, try USERPROFILE on Windows. if (rcutils_get_env("USERPROFILE", &homedir) == NULL && *homedir != '\0') { // The USERPROFILE environment variable was set and is non-empty, return it. return homedir; } +#endif // Couldn't get the home directory, return NULL. return NULL; From 0fe3bab1f96006d51a67e8850387e527a55e5188 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Mon, 6 May 2019 07:42:04 -0400 Subject: [PATCH 09/10] Make sure to #include libgen.h We need this to get basename on macOS. Signed-off-by: Chris Lalancette --- src/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/process.c b/src/process.c index 89b6710c..8a142643 100644 --- a/src/process.c +++ b/src/process.c @@ -25,6 +25,7 @@ extern "C" #if defined _WIN32 || defined __CYGWIN__ #include #else +#include #include #endif From 8dee9435b8b9a5bc6e2bc6f25c90e272ae00d07e Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Mon, 6 May 2019 07:55:52 -0400 Subject: [PATCH 10/10] Double-stars so doxygen picks it up. Signed-off-by: Chris Lalancette --- include/rcutils/get_env.h | 2 +- include/rcutils/process.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/rcutils/get_env.h b/include/rcutils/get_env.h index 787e6089..80503099 100644 --- a/include/rcutils/get_env.h +++ b/include/rcutils/get_env.h @@ -62,7 +62,7 @@ const char * rcutils_get_env(const char * env_name, const char ** env_value); /// Retrieve the full path to the home directory. -/* +/** * The c-string which is returned is only valid until the next time this * function is called, because it is a direct pointer to the static storage. * Also note that the string returned here should *not* be freed. diff --git a/include/rcutils/process.h b/include/rcutils/process.h index 2caf45bb..adc914f4 100644 --- a/include/rcutils/process.h +++ b/include/rcutils/process.h @@ -25,7 +25,7 @@ extern "C" #include "rcutils/visibility_control.h" /// Retrieve the current process ID. -/* +/** * This function returns the current process ID, and is always successful. * * This function is thread-safe. @@ -37,7 +37,7 @@ RCUTILS_WARN_UNUSED int rcutils_get_pid(void); /// Retrieve the current executable name. -/* +/** * This function portably retrieves the current program name and returns * a copy of it. * It is up to the caller to free the memory.