utils: Add thread-safe variants of dirname(3) and basename(3)

This commit is contained in:
Tobias Brunner
2014-02-24 12:04:11 +01:00
parent ba10cd3c7f
commit 766141bc77
3 changed files with 144 additions and 4 deletions
@@ -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));
+61 -3
View File
@@ -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.
*/
+27 -1
View File
@@ -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.
*