Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions include/rcutils/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,24 @@ rcutils_to_native_path(
const char * path,
rcutils_allocator_t allocator);

/// Expand user directory in path.
/**
* This function expands an initial '~' to the current user's home directory.
* The home directory is fetched using `rcutils_get_home_dir()`.
* This function returns a newly allocated string on success.
* It is up to the caller to release the memory once it is done with it by
* calling `deallocate` on the same allocator passed here.
*
* \param[in] path A null-terminated C string representing a path.
* \param[in] allocator
* \return path with expanded home directory on success, or
* \return `NULL` on invalid arguments, or
* \return `NULL` on failure.
*/
RCUTILS_PUBLIC
char *
rcutils_expand_user(const char * path, rcutils_allocator_t allocator);

/// Create the specified directory.
/**
* This function creates an absolutely-specified directory.
Expand Down
25 changes: 25 additions & 0 deletions src/filesystem.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ extern "C"

#include "rcutils/error_handling.h"
#include "rcutils/format_string.h"
#include "rcutils/get_env.h"
#include "rcutils/repl_str.h"
#include "rcutils/strdup.h"

#ifdef _WIN32
# define RCUTILS_PATH_DELIMITER "\\"
Expand Down Expand Up @@ -181,6 +183,29 @@ rcutils_to_native_path(
return rcutils_repl_str(path, "/", RCUTILS_PATH_DELIMITER, &allocator);
}

char *
rcutils_expand_user(const char * path, rcutils_allocator_t allocator)
{
if (NULL == path) {
return NULL;
}

if ('~' != path[0]) {
return rcutils_strdup(path, allocator);
}

const char * homedir = rcutils_get_home_dir();
if (NULL == homedir) {
return NULL;
}
return rcutils_format_string_limit(
allocator,
strlen(homedir) + strlen(path),
"%s%s",
homedir,
path + 1);
}

bool
rcutils_mkdir(const char * abs_path)
{
Expand Down
57 changes: 57 additions & 0 deletions test/test_filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <string>

#include "rcutils/filesystem.h"
#include "rcutils/get_env.h"

#include "osrf_testing_tools_cpp/scope_exit.hpp"

Expand Down Expand Up @@ -307,6 +308,62 @@ TEST_F(TestFilesystemFixture, is_readable_and_writable) {
}
}

TEST_F(TestFilesystemFixture, expand_user) {
const char * homedir = rcutils_get_home_dir();
ASSERT_STRNE(NULL, homedir);
const std::string homedir_str(homedir);

{
// Invalid path arg
EXPECT_EQ(NULL, rcutils_expand_user(NULL, g_allocator));
}
{
// No ~
const char * path = "/this/path/has/no/tilde";
char * ret_path = rcutils_expand_user(path, g_allocator);
EXPECT_STREQ(ret_path, path);
ASSERT_NE(ret_path, path);
g_allocator.deallocate(ret_path, g_allocator.state);
}
{
// No ~ and empty path
const char * path = "";
char * ret_path = rcutils_expand_user(path, g_allocator);
EXPECT_STREQ(ret_path, path);
ASSERT_NE(ret_path, path);
g_allocator.deallocate(ret_path, g_allocator.state);
}
{
// With ~ but not leading
const char * path = "/prefix/~/my/dir";
char * ret_path = rcutils_expand_user(path, g_allocator);
EXPECT_STREQ(ret_path, path);
ASSERT_NE(ret_path, path);
g_allocator.deallocate(ret_path, g_allocator.state);
}
{
// With ~ only
const char * path = "~";
char * ret_path = rcutils_expand_user(path, g_allocator);
EXPECT_STREQ(ret_path, homedir);
g_allocator.deallocate(ret_path, g_allocator.state);
}
{
// With ~/ only
const char * path = "~/";
char * ret_path = rcutils_expand_user(path, g_allocator);
EXPECT_STREQ(ret_path, (homedir_str + "/").c_str());
g_allocator.deallocate(ret_path, g_allocator.state);
}
{
// Normal use-case
const char * path = "~/my/directory";
char * ret_path = rcutils_expand_user(path, g_allocator);
EXPECT_STREQ(ret_path, (homedir_str + "/my/directory").c_str());
g_allocator.deallocate(ret_path, g_allocator.state);
}
}

TEST_F(TestFilesystemFixture, mkdir) {
{
// Make a new directory
Expand Down