]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
utils: Add thread-safe variants of dirname(3) and basename(3)
authorTobias Brunner <tobias@strongswan.org>
Fri, 21 Feb 2014 17:44:15 +0000 (18:44 +0100)
committerTobias Brunner <tobias@strongswan.org>
Mon, 24 Feb 2014 11:04:11 +0000 (12:04 +0100)
src/libstrongswan/tests/suites/test_utils.c
src/libstrongswan/utils/utils.c
src/libstrongswan/utils/utils.h

index 2d290f81e0ba2aeea4ff1a6916a7dec3caae433d..92f65596adff4da1305b5c074372933717a12daa 100644 (file)
@@ -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));
index e9f8b1892d3fe38b022a8541515219542ef483d8..406c5c811219c2eb4dd0c08eee6d3c37e4225079 100644 (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.
  */
index 0b26ba53495b8087542252aa4ea80d71f1b1b2a4..4c113900e38e6be1e542e92ef71fd3446c42ea9c 100644 (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.
  *