aboutsummaryrefslogtreecommitdiff
path: root/path.c
diff options
context:
space:
mode:
authorDavid Reiss <dreiss@facebook.com>2008-05-19 23:48:54 -0700
committerJunio C Hamano <gitster@pobox.com>2008-05-23 14:11:20 -0700
commitae299be0e5e610027e6492d48d70c1cbb0e9edd8 (patch)
tree247e12f709c96df4eea12e5759c689a630b02143 /path.c
parent377d9c409ffe0f0d994b929aeb94716139207b9d (diff)
downloadgit-ae299be0e5e610027e6492d48d70c1cbb0e9edd8.tar.gz
git-ae299be0e5e610027e6492d48d70c1cbb0e9edd8.tar.xz
Implement normalize_absolute_path
normalize_absolute_path removes several oddities form absolute paths, giving nice clean paths like "/dir/sub1/sub2". Also add a test case for this utility, based on a new test program (in the style of test-sha1). Signed-off-by: David Reiss <dreiss@facebook.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'path.c')
-rw-r--r--path.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/path.c b/path.c
index b7c24a2aa..7175a06ed 100644
--- a/path.c
+++ b/path.c
@@ -357,3 +357,56 @@ const char *make_absolute_path(const char *path)
return buf;
}
+
+/*
+ * path = absolute path
+ * buf = buffer of at least max(2, strlen(path)+1) bytes
+ * It is okay if buf == path, but they should not overlap otherwise.
+ *
+ * Performs the following normalizations on path, storing the result in buf:
+ * - Removes trailing slashes.
+ * - Removes empty components.
+ * - Removes "." components.
+ * - Removes ".." components, and the components the precede them.
+ * "" and paths that contain only slashes are normalized to "/".
+ * Returns the length of the output.
+ *
+ * Note that this function is purely textual. It does not follow symlinks,
+ * verify the existence of the path, or make any system calls.
+ */
+int normalize_absolute_path(char *buf, const char *path)
+{
+ const char *comp_start = path, *comp_end = path;
+ char *dst = buf;
+ int comp_len;
+ assert(buf);
+ assert(path);
+
+ while (*comp_start) {
+ assert(*comp_start == '/');
+ while (*++comp_end && *comp_end != '/')
+ ; /* nothing */
+ comp_len = comp_end - comp_start;
+
+ if (!strncmp("/", comp_start, comp_len) ||
+ !strncmp("/.", comp_start, comp_len))
+ goto next;
+
+ if (!strncmp("/..", comp_start, comp_len)) {
+ while (dst > buf && *--dst != '/')
+ ; /* nothing */
+ goto next;
+ }
+
+ memcpy(dst, comp_start, comp_len);
+ dst += comp_len;
+ next:
+ comp_start = comp_end;
+ }
+
+ if (dst == buf)
+ *dst++ = '/';
+
+ *dst = '\0';
+ return dst - buf;
+}