Add git__dirname and git__basename utility routines These routines are intended to extract the directory and base name from a path string. Note that these routines do not interact with any filesystem and work only on the text of the path. Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
diff --git a/src/util.c b/src/util.c
index 80829e6..3184a3a 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 8f0c4b5..3f541ff 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 9e4700a..8399c6e 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