Commit ced645ea9ca4170bd75c17cb9c2c8f19f935491d

Ramsay Jones 2009-01-12T19:42:13

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>

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