[PATCH] Give show-files the ability to process exclusion pattern.
authorNicolas Pitre <nico@cam.org>
Thu, 28 Apr 2005 18:44:04 +0000 (11:44 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 28 Apr 2005 18:44:04 +0000 (11:44 -0700)
This can be used with the famous dontdiff file as follows to find out
about uncommitted files just like dontdiff is used with the diff
command:

    show-files --others --exclude-from=dontdiff

and the exclude list can be reversed with the --ignore switch.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
show-files.c

index afeb635..9bb8fdb 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #include <dirent.h>
+#include <fnmatch.h>
 
 #include "cache.h"
 
@@ -17,6 +18,70 @@ static int show_stage = 0;
 static int show_unmerged = 0;
 static int line_terminator = '\n';
 
+static int nr_excludes;
+static const char **excludes;
+static int excludes_alloc;
+
+static void add_exclude(const char *string)
+{
+       if (nr_excludes == excludes_alloc) {
+               excludes_alloc = alloc_nr(excludes_alloc);
+               excludes = realloc(excludes, excludes_alloc*sizeof(char *));
+       }
+       excludes[nr_excludes++] = string;
+}
+
+static void add_excludes_from_file(const char *fname)
+{
+       int fd, i;
+       long size;
+       char *buf, *entry;
+
+       fd = open(fname, O_RDONLY);
+       if (fd < 0)
+               goto err;
+       size = lseek(fd, 0, SEEK_END);
+       if (size < 0)
+               goto err;
+       lseek(fd, 0, SEEK_SET);
+       if (size == 0) {
+               close(fd);
+               return;
+       }
+       buf = xmalloc(size);
+       if (read(fd, buf, size) != size)
+               goto err;
+       close(fd);
+
+       entry = buf;
+       for (i = 0; i < size; i++) {
+               if (buf[i] == '\n') {
+                       if (entry != buf + i) {
+                               buf[i] = 0;
+                               add_exclude(entry);
+                       }
+                       entry = buf + i + 1;
+               }
+       }
+       return;
+
+err:   perror(fname);
+       exit(1);
+}
+
+static int excluded(const char *pathname)
+{
+       int i;
+       if (nr_excludes) {
+               const char *basename = strrchr(pathname, '/');
+               basename = (basename) ? basename+1 : pathname;
+               for (i = 0; i < nr_excludes; i++)
+                       if (fnmatch(excludes[i], basename, 0) == 0)
+                               return 1;
+       }
+       return 0;
+}
+
 static const char **dir;
 static int nr_dir;
 static int dir_alloc;
@@ -59,6 +124,8 @@ static void read_directory(const char *path, const char *base, int baselen)
 
                        if (de->d_name[0] == '.')
                                continue;
+                       if (excluded(de->d_name) != show_ignored)
+                               continue;
                        len = strlen(de->d_name);
                        memcpy(fullname + baselen, de->d_name, len+1);
 
@@ -101,17 +168,17 @@ static void show_files(void)
        int i;
 
        /* For cached/deleted files we don't need to even do the readdir */
-       if (show_others | show_ignored) {
+       if (show_others) {
                read_directory(".", "", 0);
                qsort(dir, nr_dir, sizeof(char *), cmp_name);
-       }
-       if (show_others) {
                for (i = 0; i < nr_dir; i++)
                        printf("%s%c", dir[i], line_terminator);
        }
        if (show_cached | show_stage) {
                for (i = 0; i < active_nr; i++) {
                        struct cache_entry *ce = active_cache[i];
+                       if (excluded(ce->name) != show_ignored)
+                               continue;
                        if (show_unmerged && !ce_stage(ce))
                                continue;
                        if (!show_stage)
@@ -130,14 +197,13 @@ static void show_files(void)
                for (i = 0; i < active_nr; i++) {
                        struct cache_entry *ce = active_cache[i];
                        struct stat st;
+                       if (excluded(ce->name) != show_ignored)
+                               continue;
                        if (!stat(ce->name, &st))
                                continue;
                        printf("%s%c", ce->name, line_terminator);
                }
        }
-       if (show_ignored) {
-               /* We don't have any "ignore" list yet */
-       }
 }
 
 int main(int argc, char **argv)
@@ -179,11 +245,34 @@ int main(int argc, char **argv)
                        continue;
                }
 
-               usage("show-files [-z] (--[cached|deleted|others|ignored|stage])*");
+               if (!strcmp(arg, "-x") && i+1 < argc) {
+                       add_exclude(argv[++i]);
+                       continue;
+               }
+               if (!strncmp(arg, "--exclude=", 10)) {
+                       add_exclude(arg+10);
+                       continue;
+               }
+               if (!strcmp(arg, "-X") && i+1 < argc) {
+                       add_excludes_from_file(argv[++i]);
+                       continue;
+               }
+               if (!strncmp(arg, "--exclude-from=", 15)) {
+                       add_excludes_from_file(arg+15);
+                       continue;
+               }
+
+               usage("show-files [-z] (--[cached|deleted|others|stage])* "
+                     "[ --ignored [--exclude=<pattern>] [--exclude-from=<file>) ]");
+       }
+
+       if (show_ignored && !nr_excludes) {
+               fprintf(stderr, "%s: --ignored needs some exclude pattern\n", argv[0]);
+               exit(1);
        }
 
        /* With no flags, we default to showing the cached files */
-       if (!(show_stage | show_deleted | show_others | show_ignored | show_unmerged))
+       if (!(show_stage | show_deleted | show_others | show_unmerged))
                show_cached = 1;
 
        read_cache();