diff --git a/CMakeLists.txt b/CMakeLists.txt index 1de77ae1..58b1cf41 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/process.c src/repl_str.c src/snprintf.c src/split.c diff --git a/include/rcutils/get_env.h b/include/rcutils/get_env.h index 29e85584..80503099 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 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. + * + * 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/include/rcutils/process.h b/include/rcutils/process.h new file mode 100644 index 00000000..adc914f4 --- /dev/null +++ b/include/rcutils/process.h @@ -0,0 +1,58 @@ +// 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__PROCESS_H_ +#define RCUTILS__PROCESS_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 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. + * + * 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_executable_name(rcutils_allocator_t allocator); + +#ifdef __cplusplus +} +#endif + +#endif // RCUTILS__PROCESS_H_ diff --git a/src/get_env.c b/src/get_env.c index 3fdff69f..c9370722 100644 --- a/src/get_env.c +++ b/src/get_env.c @@ -55,6 +55,28 @@ 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; + } + +#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; +} + #ifdef __cplusplus } #endif diff --git a/src/process.c b/src/process.c new file mode 100644 index 00000000..8a142643 --- /dev/null +++ b/src/process.c @@ -0,0 +1,104 @@ +// 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 +#include +#endif + +#include "rcutils/allocator.h" +#include "rcutils/error_handling.h" +#include "rcutils/process.h" + +int rcutils_get_pid(void) +{ +#if defined _WIN32 || defined __CYGWIN__ + return (int)GetCurrentProcessId(); +#else + return (int)getpid(); +#endif +} + +char * rcutils_get_executable_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 + char appname[MAX_PATH]; + int32_t size = GetModuleFileNameA(NULL, appname, MAX_PATH); + if (size == 0) { + return NULL; + } +#else +#error "Unsupported OS" +#endif + + 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(applen + 1, allocator.state); + if (NULL == basec) { + return NULL; + } + + // 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) { + allocator.deallocate(basec, allocator.state); + 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; +} + +#ifdef __cplusplus +} +#endif