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
|
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
|
* time_printf_hook
|
||||||
*/
|
*/
|
||||||
@@ -630,6 +681,11 @@ Suite *utils_suite_create()
|
|||||||
tcase_add_loop_test(tc, test_strreplace, 0, countof(strreplace_data));
|
tcase_add_loop_test(tc, test_strreplace, 0, countof(strreplace_data));
|
||||||
suite_add_tcase(s, tc);
|
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");
|
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_printf_hook, 0, countof(time_data));
|
||||||
tcase_add_loop_test(tc, test_time_delta_printf_hook, 0, countof(time_delta_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
|
* Copyright (C) 2005-2008 Martin Willi
|
||||||
* Hochschule fuer Technik Rapperswil
|
* Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@@ -14,8 +14,7 @@
|
|||||||
* for more details.
|
* for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "utils.h"
|
#define _GNU_SOURCE /* for memrchr */
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -27,6 +26,8 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include "collections/enumerator.h"
|
#include "collections/enumerator.h"
|
||||||
#include "utils/debug.h"
|
#include "utils/debug.h"
|
||||||
#include "utils/chunk.h"
|
#include "utils/chunk.h"
|
||||||
@@ -193,6 +194,63 @@ char* strreplace(const char *str, const char *search, const char *replace)
|
|||||||
return res;
|
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.
|
* Described in header.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2008-2013 Tobias Brunner
|
* Copyright (C) 2008-2014 Tobias Brunner
|
||||||
* Copyright (C) 2008 Martin Willi
|
* Copyright (C) 2008 Martin Willi
|
||||||
* Hochschule fuer Technik Rapperswil
|
* 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);
|
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.
|
* Creates a directory and all required parent directories.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user