Code

[PATCH] Improve handling of "." and ".." in git-diff-*
authorLinus Torvalds <torvalds@osdl.org>
Wed, 17 Aug 2005 03:44:32 +0000 (20:44 -0700)
committerJunio C Hamano <junkio@cox.net>
Wed, 17 Aug 2005 04:33:25 +0000 (21:33 -0700)
This fixes up usage of ".." (without an ending slash) and "." (with or
without the ending slash) in the git diff family.

It also fixes pathspec matching for the case of an empty pathspec, since a
"." in the top-level directory (or enough ".." under subdirectories) will
result in an empty pathspec. We used to not match it against anything, but
it should in fact match everything.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
diffcore-pathspec.c
read-cache.c
setup.c

index a48acbc965d5187fc9abb3ffab4fc9e60d4feac3..68fe009132d1e900138a9d61bb7c658e23d9b76d 100644 (file)
@@ -29,6 +29,8 @@ static int matches_pathspec(const char *name, struct path_spec *s, int cnt)
                    name[len] == 0 ||
                    name[len] == '/')
                        return 1;
+               if (!len)
+                       return 1;
        }
        return 0;
 }
index 5820f18d9a79fd83ff5a418a5dfc68bbf7c5c354..ced597318e783ab08b73c88f8b724be51f3b3dec 100644 (file)
@@ -191,6 +191,8 @@ int ce_path_match(const struct cache_entry *ce, const char **pathspec)
                        return 1;
                if (name[matchlen] == '/' || !name[matchlen])
                        return 1;
+               if (!matchlen)
+                       return 1;
        }
        return 0;
 }
diff --git a/setup.c b/setup.c
index 896fca5032ac49758904532124be6f3b4bbab625..1710b1685463e481d1c7ff5471bee6774d4b9c32 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -1,23 +1,60 @@
 #include "cache.h"
 
+static char *prefix_path(const char *prefix, int len, char *path)
+{
+       char *orig = path;
+       for (;;) {
+               char c;
+               if (*path != '.')
+                       break;
+               c = path[1];
+               /* "." */
+               if (!c) {
+                       path++;
+                       break;
+               }
+               /* "./" */
+               if (c == '/') {
+                       path += 2;
+                       continue;
+               }
+               if (c != '.')
+                       break;
+               c = path[2];
+               if (!c)
+                       path += 2;
+               else if (c == '/')
+                       path += 3;
+               else
+                       break;
+               /* ".." and "../" */
+               /* Remove last component of the prefix */
+               do {
+                       if (!len)
+                               die("'%s' is outside repository", orig);
+                       len--;
+               } while (len && prefix[len-1] != '/');
+               continue;
+       }
+       if (len) {
+               int speclen = strlen(path);
+               char *n = xmalloc(speclen + len + 1);
+       
+               memcpy(n, prefix, len);
+               memcpy(n + len, path, speclen+1);
+               path = n;
+       }
+       return path;
+}
+
 const char **get_pathspec(const char *prefix, char **pathspec)
 {
        char *entry = *pathspec;
        char **p;
        int prefixlen;
 
-       if (!prefix) {
-               char **p;
-               if (!entry)
-                       return NULL;
-               p = pathspec;
-               do {
-                       if (*entry != '.')
-                               continue;
-                       /* fixup ? */
-               } while ((entry = *++p) != NULL);
-               return (const char **) pathspec;
-       }
+       if (!prefix && !entry)
+               return NULL;
 
        if (!entry) {
                static const char *spec[2];
@@ -27,38 +64,10 @@ const char **get_pathspec(const char *prefix, char **pathspec)
        }
 
        /* Otherwise we have to re-write the entries.. */
-       prefixlen = strlen(prefix);
        p = pathspec;
+       prefixlen = prefix ? strlen(prefix) : 0;
        do {
-               int speclen, len = prefixlen;
-               char *n;
-
-               for (;;) {
-                       if (!strcmp(entry, ".")) {
-                               entry++;
-                               break;
-                       }
-                       if (!strncmp(entry, "./", 2)) {
-                               entry += 2;
-                               continue;
-                       }
-                       if (!strncmp(entry, "../", 3)) {
-                               do {
-                                       if (!len)
-                                               die("'%s' is outside repository", *p);
-                                       len--;
-                               } while (len && prefix[len-1] != '/');
-                               entry += 3;
-                               continue;
-                       }
-                       break;
-               }
-               speclen = strlen(entry);
-               n = xmalloc(speclen + len + 1);
-               
-               memcpy(n, prefix, len);
-               memcpy(n + len, entry, speclen+1);
-               *p = n;
+               *p = prefix_path(prefix, prefixlen, entry);
        } while ((entry = *++p) != NULL);
        return (const char **) pathspec;
 }