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>
David Reiss committed
May 19, 2008 at 23:48 UTC
ae299be0e5e610027e6492d48d70c1cbb0e9edd8
6 files changed
+109
-1
.gitignore
+1
@@ -150,6 +150,7 @@ test-dump-cache-tree
150
test-genrandom
151
test-match-trees
152
test-parse-options
153
+test-path-utils
154
test-sha1
155
common-cmds.h
156
*.tar.gz
Makefile
+1
-1
@@ -1186,7 +1186,7 @@ endif
1186
1187
### Testing rules
1188
1189
-TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X test-parse-options$X
1189
+TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X test-parse-options$X test-path-utils$X
1190
1191
all:: $(TEST_PROGRAMS)
1192
cache.h
+1
@@ -514,6 +514,7 @@ static inline int is_absolute_path(const char *path)
514
return path[0] == '/';
515
}
516
const char *make_absolute_path(const char *path);
517
+int normalize_absolute_path(char *buf, const char *path);
518
519
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
520
extern int sha1_object_info(const unsigned char *, unsigned long *);
path.c
+53
@@ -357,3 +357,56 @@ const char *make_absolute_path(const char *path)
357
358
return buf;
359
}
360
+
361
+/*
362
+ * path = absolute path
363
+ * buf = buffer of at least max(2, strlen(path)+1) bytes
364
+ * It is okay if buf == path, but they should not overlap otherwise.
365
+ *
366
+ * Performs the following normalizations on path, storing the result in buf:
367
+ * - Removes trailing slashes.
368
+ * - Removes empty components.
369
+ * - Removes "." components.
370
+ * - Removes ".." components, and the components the precede them.
371
+ * "" and paths that contain only slashes are normalized to "/".
372
+ * Returns the length of the output.
373
+ *
374
+ * Note that this function is purely textual. It does not follow symlinks,
375
+ * verify the existence of the path, or make any system calls.
376
+ */
377
+int normalize_absolute_path(char *buf, const char *path)
378
+{
379
+ const char *comp_start = path, *comp_end = path;
380
+ char *dst = buf;
381
+ int comp_len;
382
+ assert(buf);
383
+ assert(path);
384
+
385
+ while (*comp_start) {
386
+ assert(*comp_start == '/');
387
+ while (*++comp_end && *comp_end != '/')
388
+ ; /* nothing */
389
+ comp_len = comp_end - comp_start;
390
+
391
+ if (!strncmp("/", comp_start, comp_len) ||
392
+ !strncmp("/.", comp_start, comp_len))
393
+ goto next;
394
+
395
+ if (!strncmp("/..", comp_start, comp_len)) {
396
+ while (dst > buf && *--dst != '/')
397
+ ; /* nothing */
398
+ goto next;
399
+ }
400
+
401
+ memcpy(dst, comp_start, comp_len);
402
+ dst += comp_len;
403
+ next:
404
+ comp_start = comp_end;
405
+ }
406
+
407
+ if (dst == buf)
408
+ *dst++ = '/';
409
+
410
+ *dst = '\0';
411
+ return dst - buf;
412
+}
t/t0060-path-utils.sh
new
+40
@@ -0,0 +1,40 @@
1
+#!/bin/sh
2
+#
3
+# Copyright (c) 2008 David Reiss
4
+#
5
+
6
+test_description='Test various path utilities'
7
+
8
+. ./test-lib.sh
9
+
10
+norm_abs() {
11
+ test_expect_success "normalize absolute" \
12
+ "test \$(test-path-utils normalize_absolute_path '$1') = '$2'"
13
+}
14
+
15
+norm_abs "" /
16
+norm_abs / /
17
+norm_abs // /
18
+norm_abs /// /
19
+norm_abs /. /
20
+norm_abs /./ /
21
+norm_abs /./.. /
22
+norm_abs /../. /
23
+norm_abs /./../.// /
24
+norm_abs /dir/.. /
25
+norm_abs /dir/sub/../.. /
26
+norm_abs /dir /dir
27
+norm_abs /dir// /dir
28
+norm_abs /./dir /dir
29
+norm_abs /dir/. /dir
30
+norm_abs /dir///./ /dir
31
+norm_abs /dir//sub/.. /dir
32
+norm_abs /dir/sub/../ /dir
33
+norm_abs //dir/sub/../. /dir
34
+norm_abs /dir/s1/../s2/ /dir/s2
35
+norm_abs /d1/s1///s2/..//../s3/ /d1/s3
36
+norm_abs /d1/s1//../s2/../../d2 /d2
37
+norm_abs /d1/.../d2 /d1/.../d2
38
+norm_abs /d1/..././../d2 /d1/d2
39
+
40
+test_done
test-path-utils.c
new
+13
@@ -0,0 +1,13 @@
1
+#include "cache.h"
2
+
3
+int main(int argc, char **argv)
4
+{
5
+ if (argc == 3 && !strcmp(argv[1], "normalize_absolute_path")) {
6
+ char *buf = xmalloc(strlen(argv[2])+1);
7
+ int rv = normalize_absolute_path(buf, argv[2]);
8
+ assert(strlen(buf) == rv);
9
+ puts(buf);
10
+ }
11
+
12
+ return 0;
13
+}