diff --git a/src/util.c b/src/util.c index 80829e69e..3184a3abd 100644 --- a/src/util.c +++ b/src/util.c @@ -59,3 +59,65 @@ int git__suffixcmp(const char *str, const char *suffix) return -1; return strcmp(str + (a - b), suffix); } + +int git__dirname(char *dir, size_t n, char *path) +{ + char *s; + int len; + + assert(dir && n > 1); + + if (!path || !*path || !(s = strrchr(path, '/'))) { + strcpy(dir, "."); + return 1; + } + + if (s == path) { /* "/[aaa]" */ + strcpy(dir, "/"); + return 1; + } + + if ((len = s - path) >= n) + return GIT_ERROR; + + memcpy(dir, path, len); + dir[len] = '\0'; + + return len; +} + +int git__basename(char *base, size_t n, char *path) +{ + char *s; + int len; + + assert(base && n > 1); + + if (!path || !*path) { + strcpy(base, "."); + return 1; + } + len = strlen(path); + + if (!(s = strrchr(path, '/'))) { + if (len >= n) + return GIT_ERROR; + strcpy(base, path); + return len; + } + + if (s == path && len == 1) { /* "/" */ + strcpy(base, "/"); + return 1; + } + + len -= s - path; + if (len >= n) + return GIT_ERROR; + + memcpy(base, s+1, len); + base[len] = '\0'; + + return len; +} + diff --git a/src/util.h b/src/util.h index 8f0c4b543..3f541ffa6 100644 --- a/src/util.h +++ b/src/util.h @@ -31,6 +31,9 @@ extern int git__fmt(char *, size_t, const char *, ...) extern int git__prefixcmp(const char *str, const char *prefix); extern int git__suffixcmp(const char *str, const char *suffix); +extern int git__dirname(char *dir, size_t n, char *path); +extern int git__basename(char *base, size_t n, char *path); + /** @return true if p fits into the range of a size_t */ GIT_INLINE(int) git__is_sizet(off_t p) { diff --git a/tests/t0003-strutil.c b/tests/t0003-strutil.c index 9e4700a60..8399c6e8a 100644 --- a/tests/t0003-strutil.c +++ b/tests/t0003-strutil.c @@ -65,3 +65,61 @@ END_TEST BEGIN_TEST(suffixcmp_zaz_ac) must_be_true(git__suffixcmp("zaz", "ac") > 0); END_TEST + +BEGIN_TEST(dirname) + char dir[64]; + + must_be_true(!(git__dirname(dir, sizeof(dir), NULL) < 0)); + must_be_true(!strcmp(dir, ".")); + + must_be_true(!(git__dirname(dir, sizeof(dir), "") < 0)); + must_be_true(!strcmp(dir, ".")); + + must_be_true(!(git__dirname(dir, sizeof(dir), "a") < 0)); + must_be_true(!strcmp(dir, ".")); + + must_be_true(!(git__dirname(dir, sizeof(dir), "/") < 0)); + must_be_true(!strcmp(dir, "/")); + + must_be_true(!(git__dirname(dir, sizeof(dir), "/usr") < 0)); + must_be_true(!strcmp(dir, "/")); + + /* TODO: should this be "/" instead (ie strip trailing / first) */ + must_be_true(!(git__dirname(dir, sizeof(dir), "/usr/") < 0)); + must_be_true(!strcmp(dir, "/usr")); + + must_be_true(!(git__dirname(dir, sizeof(dir), "/usr/lib") < 0)); + must_be_true(!strcmp(dir, "/usr")); + + must_be_true(!(git__dirname(dir, sizeof(dir), "usr/lib") < 0)); + must_be_true(!strcmp(dir, "usr")); +END_TEST + +BEGIN_TEST(basename) + char base[64]; + + must_be_true(!(git__basename(base, sizeof(base), NULL) < 0)); + must_be_true(!strcmp(base, ".")); + + must_be_true(!(git__basename(base, sizeof(base), "") < 0)); + must_be_true(!strcmp(base, ".")); + + must_be_true(!(git__basename(base, sizeof(base), "a") < 0)); + must_be_true(!strcmp(base, "a")); + + must_be_true(!(git__basename(base, sizeof(base), "/") < 0)); + must_be_true(!strcmp(base, "/")); + + must_be_true(!(git__basename(base, sizeof(base), "/usr") < 0)); + must_be_true(!strcmp(base, "usr")); + + /* TODO: should this be "usr" instead (ie strip trailing / first) */ + must_be_true(!(git__basename(base, sizeof(base), "/usr/") < 0)); + must_be_true(!strcmp(base, "")); + + must_be_true(!(git__basename(base, sizeof(base), "/usr/lib") < 0)); + must_be_true(!strcmp(base, "lib")); + + must_be_true(!(git__basename(base, sizeof(base), "usr/lib") < 0)); + must_be_true(!strcmp(base, "lib")); +END_TEST