utils: Add thread-safe variants of dirname(3) and basename(3)
This commit is contained in:
@@ -467,6 +467,57 @@ START_TEST(test_strreplace)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/*******************************************************************************
|
||||
* path_dirname/basename
|
||||
*/
|
||||
|
||||
static struct {
|
||||
char *path;
|
||||
char *dir;
|
||||
char *base;
|
||||
} path_data[] = {
|
||||
{NULL, ".", "."},
|
||||
{"", ".", "."},
|
||||
{".", ".", "."},
|
||||
{"..", ".", ".."},
|
||||
{"/", "/", "/"},
|
||||
{"//", "/", "/"},
|
||||
{"foo", ".", "foo"},
|
||||
{"f/", ".", "f"},
|
||||
{"foo/", ".", "foo"},
|
||||
{"foo//", ".", "foo"},
|
||||
{"/f", "/", "f"},
|
||||
{"/f/", "/", "f"},
|
||||
{"/foo", "/", "foo"},
|
||||
{"/foo/", "/", "foo"},
|
||||
{"//foo/", "/", "foo"},
|
||||
{"foo/bar", "foo", "bar"},
|
||||
{"foo//bar", "foo", "bar"},
|
||||
{"/foo/bar", "/foo", "bar"},
|
||||
{"/foo/bar/", "/foo", "bar"},
|
||||
{"/foo/bar/baz", "/foo/bar", "baz"},
|
||||
};
|
||||
|
||||
START_TEST(test_path_dirname)
|
||||
{
|
||||
char *dir;
|
||||
|
||||
dir = path_dirname(path_data[_i].path);
|
||||
ck_assert_str_eq(path_data[_i].dir, dir);
|
||||
free(dir);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_path_basename)
|
||||
{
|
||||
char *base;
|
||||
|
||||
base = path_basename(path_data[_i].path);
|
||||
ck_assert_str_eq(path_data[_i].base, base);
|
||||
free(base);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/*******************************************************************************
|
||||
* time_printf_hook
|
||||
*/
|
||||
@@ -630,6 +681,11 @@ Suite *utils_suite_create()
|
||||
tcase_add_loop_test(tc, test_strreplace, 0, countof(strreplace_data));
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("path_dirname/basename");
|
||||
tcase_add_loop_test(tc, test_path_dirname, 0, countof(path_data));
|
||||
tcase_add_loop_test(tc, test_path_basename, 0, countof(path_data));
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("printf_hooks");
|
||||
tcase_add_loop_test(tc, test_time_printf_hook, 0, countof(time_data));
|
||||
tcase_add_loop_test(tc, test_time_delta_printf_hook, 0, countof(time_delta_data));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2013 Tobias Brunner
|
||||
* Copyright (C) 2008-2014 Tobias Brunner
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -14,8 +14,7 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define _GNU_SOURCE /* for memrchr */
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@@ -27,6 +26,8 @@
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include "collections/enumerator.h"
|
||||
#include "utils/debug.h"
|
||||
#include "utils/chunk.h"
|
||||
@@ -193,6 +194,63 @@ char* strreplace(const char *str, const char *search, const char *replace)
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
char* path_dirname(const char *path)
|
||||
{
|
||||
char *pos;
|
||||
|
||||
pos = path ? strrchr(path, '/') : NULL;
|
||||
|
||||
if (pos && !pos[1])
|
||||
{ /* if path ends with slashes we have to look beyond them */
|
||||
while (pos > path && *pos == '/')
|
||||
{ /* skip trailing slashes */
|
||||
pos--;
|
||||
}
|
||||
pos = memrchr(path, '/', pos - path + 1);
|
||||
}
|
||||
if (!pos)
|
||||
{
|
||||
return strdup(".");
|
||||
}
|
||||
while (pos > path && *pos == '/')
|
||||
{ /* skip superfluous slashes */
|
||||
pos--;
|
||||
}
|
||||
return strndup(path, pos - path + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
char* path_basename(const char *path)
|
||||
{
|
||||
char *pos, *trail = NULL;
|
||||
|
||||
if (!path || !*path)
|
||||
{
|
||||
return strdup(".");
|
||||
}
|
||||
pos = strrchr(path, '/');
|
||||
if (pos && !pos[1])
|
||||
{ /* if path ends with slashes we have to look beyond them */
|
||||
while (pos > path && *pos == '/')
|
||||
{ /* skip trailing slashes */
|
||||
pos--;
|
||||
}
|
||||
if (pos == path && *pos == '/')
|
||||
{ /* contains only slashes */
|
||||
return strdup("/");
|
||||
}
|
||||
trail = pos + 1;
|
||||
pos = memrchr(path, '/', trail - path);
|
||||
}
|
||||
pos = pos ? pos + 1 : (char*)path;
|
||||
return trail ? strndup(pos, trail - pos) : strdup(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2013 Tobias Brunner
|
||||
* Copyright (C) 2008-2014 Tobias Brunner
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -486,6 +486,32 @@ char *translate(char *str, const char *from, const char *to);
|
||||
*/
|
||||
char *strreplace(const char *str, const char *search, const char *replace);
|
||||
|
||||
/**
|
||||
* Like dirname(3) returns the directory part of the given null-terminated
|
||||
* pathname, up to but not including the final '/' (or '.' if no '/' is found).
|
||||
* Trailing '/' are not counted as part of the pathname.
|
||||
*
|
||||
* The difference is that it does this in a thread-safe manner (i.e. it does not
|
||||
* use static buffers) and does not modify the original path.
|
||||
*
|
||||
* @param path original pathname
|
||||
* @return allocated directory component
|
||||
*/
|
||||
char *path_dirname(const char *path);
|
||||
|
||||
/**
|
||||
* Like basename(3) returns the filename part of the given null-terminated path,
|
||||
* i.e. the part following the final '/' (or '.' if path is empty or NULL).
|
||||
* Trailing '/' are not counted as part of the pathname.
|
||||
*
|
||||
* The difference is that it does this in a thread-safe manner (i.e. it does not
|
||||
* use static buffers) and does not modify the original path.
|
||||
*
|
||||
* @param path original pathname
|
||||
* @return allocated filename component
|
||||
*/
|
||||
char *path_basename(const char *path);
|
||||
|
||||
/**
|
||||
* Creates a directory and all required parent directories.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user