Merge part of 'jc/cache-tree'
[gitweb.git] / ls-files.c
index 585f6a7ff2aa4f3bf6c9273bd6f87a2fb37ab64a..4a4af1ca3b3cc11e2996c2889cb8ea16bbb0dded 100644 (file)
@@ -21,6 +21,7 @@ static int show_unmerged = 0;
 static int show_modified = 0;
 static int show_killed = 0;
 static int show_other_directories = 0;
+static int hide_empty_directories = 0;
 static int show_valid_bit = 0;
 static int line_terminator = '\n';
 
@@ -93,11 +94,12 @@ static int add_excludes_from_file_1(const char *fname,
                close(fd);
                return 0;
        }
-       buf = xmalloc(size);
+       buf = xmalloc(size+1);
        if (read(fd, buf, size) != size)
                goto err;
        close(fd);
 
+       buf[size++] = '\n';
        entry = buf;
        for (i = 0; i < size; i++) {
                if (buf[i] == '\n') {
@@ -258,11 +260,12 @@ static int dir_exists(const char *dirname, int len)
  * Also, we ignore the name ".git" (even if it is not a directory).
  * That likely will not change.
  */
-static void read_directory(const char *path, const char *base, int baselen)
+static int read_directory(const char *path, const char *base, int baselen)
 {
-       DIR *dir = opendir(path);
+       DIR *fdir = opendir(path);
+       int contents = 0;
 
-       if (dir) {
+       if (fdir) {
                int exclude_stk;
                struct dirent *de;
                char fullname[MAXPATHLEN + 1];
@@ -270,7 +273,7 @@ static void read_directory(const char *path, const char *base, int baselen)
 
                exclude_stk = push_exclude_per_directory(base, baselen);
 
-               while ((de = readdir(dir)) != NULL) {
+               while ((de = readdir(fdir)) != NULL) {
                        int len;
 
                        if ((de->d_name[0] == '.') &&
@@ -288,6 +291,7 @@ static void read_directory(const char *path, const char *base, int baselen)
 
                        switch (DTYPE(de)) {
                        struct stat st;
+                       int subdir, rewind_base;
                        default:
                                continue;
                        case DT_UNKNOWN:
@@ -301,22 +305,32 @@ static void read_directory(const char *path, const char *base, int baselen)
                        case DT_DIR:
                                memcpy(fullname + baselen + len, "/", 2);
                                len++;
+                               rewind_base = nr_dir;
+                               subdir = read_directory(fullname, fullname,
+                                                       baselen + len);
                                if (show_other_directories &&
-                                   !dir_exists(fullname, baselen + len))
+                                   (subdir || !hide_empty_directories) &&
+                                   !dir_exists(fullname, baselen + len)) {
+                                       // Rewind the read subdirectory
+                                       while (nr_dir > rewind_base)
+                                               free(dir[--nr_dir]);
                                        break;
-                               read_directory(fullname, fullname,
-                                              baselen + len);
+                               }
+                               contents += subdir;
                                continue;
                        case DT_REG:
                        case DT_LNK:
                                break;
                        }
                        add_name(fullname, baselen + len);
+                       contents++;
                }
-               closedir(dir);
+               closedir(fdir);
 
                pop_exclude_per_directory(exclude_stk);
        }
+
+       return contents;
 }
 
 static int cmp_name(const void *p1, const void *p2)
@@ -698,6 +712,10 @@ int main(int argc, const char **argv)
                        show_other_directories = 1;
                        continue;
                }
+               if (!strcmp(arg, "--no-empty-directory")) {
+                       hide_empty_directories = 1;
+                       continue;
+               }
                if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
                        /* There's no point in showing unmerged unless
                         * you also show the stage information.