summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ls-files.c102
1 files changed, 73 insertions, 29 deletions
diff --git a/ls-files.c b/ls-files.c
index fadfa01..41a1f9d 100644
--- a/ls-files.c
+++ b/ls-files.c
@@ -26,30 +26,45 @@ static const char *tag_other = "";
static const char *tag_killed = "";
static char *exclude_per_dir = NULL;
-static int nr_excludes;
-static int excludes_alloc;
-static struct exclude {
- const char *pattern;
- const char *base;
- int baselen;
-} **excludes;
-
-static void add_exclude(const char *string, const char *base, int baselen)
+
+/* We maintain three exclude pattern lists:
+ * EXC_CMDL lists patterns explicitly given on the command line.
+ * EXC_DIRS lists patterns obtained from per-directory ignore files.
+ * EXC_FILE lists patterns from fallback ignore files.
+ */
+#define EXC_CMDL 0
+#define EXC_DIRS 1
+#define EXC_FILE 2
+static struct exclude_list {
+ int nr;
+ int alloc;
+ struct exclude {
+ const char *pattern;
+ const char *base;
+ int baselen;
+ } **excludes;
+} exclude_list[3];
+
+static void add_exclude(const char *string, const char *base,
+ int baselen, struct exclude_list *which)
{
struct exclude *x = xmalloc(sizeof (*x));
x->pattern = string;
x->base = base;
x->baselen = baselen;
- if (nr_excludes == excludes_alloc) {
- excludes_alloc = alloc_nr(excludes_alloc);
- excludes = realloc(excludes, excludes_alloc*sizeof(char *));
+ if (which->nr == which->alloc) {
+ which->alloc = alloc_nr(which->alloc);
+ which->excludes = realloc(which->excludes,
+ which->alloc * sizeof(x));
}
- excludes[nr_excludes++] = x;
+ which->excludes[which->nr++] = x;
}
static int add_excludes_from_file_1(const char *fname,
- const char *base, int baselen)
+ const char *base,
+ int baselen,
+ struct exclude_list *which)
{
int fd, i;
long size;
@@ -76,7 +91,7 @@ static int add_excludes_from_file_1(const char *fname,
if (buf[i] == '\n') {
if (entry != buf + i && entry[0] != '#') {
buf[i] = 0;
- add_exclude(entry, base, baselen);
+ add_exclude(entry, base, baselen, which);
}
entry = buf + i + 1;
}
@@ -91,38 +106,45 @@ static int add_excludes_from_file_1(const char *fname,
static void add_excludes_from_file(const char *fname)
{
- if (add_excludes_from_file_1(fname, "", 0) < 0)
+ if (add_excludes_from_file_1(fname, "", 0,
+ &exclude_list[EXC_FILE]) < 0)
die("cannot use %s as an exclude file", fname);
}
static int push_exclude_per_directory(const char *base, int baselen)
{
char exclude_file[PATH_MAX];
- int current_nr = nr_excludes;
+ struct exclude_list *el = &exclude_list[EXC_DIRS];
+ int current_nr = el->nr;
if (exclude_per_dir) {
memcpy(exclude_file, base, baselen);
strcpy(exclude_file + baselen, exclude_per_dir);
- add_excludes_from_file_1(exclude_file, base, baselen);
+ add_excludes_from_file_1(exclude_file, base, baselen, el);
}
return current_nr;
}
static void pop_exclude_per_directory(int stk)
{
- while (stk < nr_excludes)
- free(excludes[--nr_excludes]);
+ struct exclude_list *el = &exclude_list[EXC_DIRS];
+
+ while (stk < el->nr)
+ free(el->excludes[--el->nr]);
}
-static int excluded(const char *pathname)
+/* Scan the list and let the last match determines the fate.
+ * Return 1 for exclude, 0 for include and -1 for undecided.
+ */
+static int excluded_1(const char *pathname,
+ int pathlen,
+ struct exclude_list *el)
{
int i;
- if (nr_excludes) {
- int pathlen = strlen(pathname);
-
- for (i = 0; i < nr_excludes; i++) {
- struct exclude *x = excludes[i];
+ if (el->nr) {
+ for (i = el->nr - 1; 0 <= i; i--) {
+ struct exclude *x = el->excludes[i];
const char *exclude = x->pattern;
int to_exclude = 1;
@@ -158,6 +180,22 @@ static int excluded(const char *pathname)
}
}
}
+ return -1; /* undecided */
+}
+
+static int excluded(const char *pathname)
+{
+ int pathlen = strlen(pathname);
+ int st;
+
+ for (st = EXC_CMDL; st <= EXC_FILE; st++) {
+ switch (excluded_1(pathname, pathlen, &exclude_list[st])) {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ }
+ }
return 0;
}
@@ -371,6 +409,7 @@ static const char *ls_files_usage =
int main(int argc, char **argv)
{
int i;
+ int exc_given = 0;
for (i = 1; i < argc; i++) {
char *arg = argv[i];
@@ -402,20 +441,25 @@ int main(int argc, char **argv)
show_stage = 1;
show_unmerged = 1;
} else if (!strcmp(arg, "-x") && i+1 < argc) {
- add_exclude(argv[++i], "", 0);
+ exc_given = 1;
+ add_exclude(argv[++i], "", 0, &exclude_list[EXC_CMDL]);
} else if (!strncmp(arg, "--exclude=", 10)) {
- add_exclude(arg+10, "", 0);
+ exc_given = 1;
+ add_exclude(arg+10, "", 0, &exclude_list[EXC_CMDL]);
} else if (!strcmp(arg, "-X") && i+1 < argc) {
+ exc_given = 1;
add_excludes_from_file(argv[++i]);
} else if (!strncmp(arg, "--exclude-from=", 15)) {
+ exc_given = 1;
add_excludes_from_file(arg+15);
} else if (!strncmp(arg, "--exclude-per-directory=", 24)) {
+ exc_given = 1;
exclude_per_dir = arg + 24;
} else
usage(ls_files_usage);
}
- if (show_ignored && !nr_excludes) {
+ if (show_ignored && !exc_given) {
fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
argv[0]);
exit(1);