X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=ls-files.c;h=df93cf2263e34cba6f0dcb9f63c01cef368434e3;hb=39c015c556f285106931e0500f301de462b0e46e;hp=841c98a710d6fbe58f21e8ab2e9b613fb592d7f3;hpb=9518eb262980d5048ef71e4450ef2cf78d7df6b5;p=git.git diff --git a/ls-files.c b/ls-files.c index 841c98a7..df93cf22 100644 --- a/ls-files.c +++ b/ls-files.c @@ -25,6 +25,8 @@ static int line_terminator = '\n'; static int prefix_len = 0, prefix_offset = 0; static const char *prefix = NULL; static const char **pathspec = NULL; +static int error_unmatch = 0; +static char *ps_matched = NULL; static const char *tag_cached = ""; static const char *tag_unmerged = ""; @@ -209,7 +211,7 @@ static int excluded(const char *pathname) struct nond_on_fs { int len; - char name[0]; + char name[FLEX_ARRAY]; /* more */ }; static struct nond_on_fs **dir; @@ -240,11 +242,9 @@ static int dir_exists(const char *dirname, int len) if (pos >= 0) return 1; pos = -pos-1; - if (pos >= active_nr) + if (pos >= active_nr) /* can't */ return 0; - if (strncmp(active_cache[pos]->name, dirname, len)) - return 0; - return active_cache[pos]->name[len] == '/'; + return !strncmp(active_cache[pos]->name, dirname, len); } /* @@ -294,13 +294,13 @@ static void read_directory(const char *path, const char *base, int baselen) continue; /* fallthrough */ case DT_DIR: - if (show_other_directories) { - if (!dir_exists(fullname, baselen + len)) - break; - } memcpy(fullname + baselen + len, "/", 2); + len++; + if (show_other_directories && + !dir_exists(fullname, baselen + len)) + break; read_directory(fullname, fullname, - baselen + len + 1); + baselen + len); continue; case DT_REG: case DT_LNK: @@ -327,7 +327,8 @@ static int cmp_name(const void *p1, const void *p2) * Match a pathspec against a filename. The first "len" characters * are the common prefix */ -static int match(const char **spec, const char *filename, int len) +static int match(const char **spec, char *ps_matched, + const char *filename, int len) { const char *m; @@ -335,17 +336,24 @@ static int match(const char **spec, const char *filename, int len) int matchlen = strlen(m + len); if (!matchlen) - return 1; + goto matched; if (!strncmp(m + len, filename + len, matchlen)) { if (m[len + matchlen - 1] == '/') - return 1; + goto matched; switch (filename[len + matchlen]) { case '/': case '\0': - return 1; + goto matched; } } if (!fnmatch(m + len, filename + len, 0)) - return 1; + goto matched; + if (ps_matched) + ps_matched++; + continue; + matched: + if (ps_matched) + *ps_matched = 1; + return 1; } return 0; } @@ -358,7 +366,7 @@ static void show_dir_entry(const char *tag, struct nond_on_fs *ent) if (len >= ent->len) die("git-ls-files: internal error - directory entry not superset of prefix"); - if (pathspec && !match(pathspec, ent->name, len)) + if (pathspec && !match(pathspec, ps_matched, ent->name, len)) return; fputs(tag, stdout); @@ -446,7 +454,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) if (len >= ce_namelen(ce)) die("git-ls-files: internal error - cache entry not superset of prefix"); - if (pathspec && !match(pathspec, ce->name, len)) + if (pathspec && !match(pathspec, ps_matched, ce->name, len)) return; if (!show_stage) { @@ -476,8 +484,28 @@ static void show_files(void) const char *path = ".", *base = ""; int baselen = prefix_len; - if (baselen) + if (baselen) { path = base = prefix; + if (exclude_per_dir) { + char *p, *pp = xmalloc(baselen+1); + memcpy(pp, prefix, baselen+1); + p = pp; + while (1) { + char save = *p; + *p = 0; + push_exclude_per_directory(pp, p-pp); + *p++ = save; + if (!save) + break; + p = strchr(p, '/'); + if (p) + p++; + else + p = pp + baselen; + } + free(pp); + } + } read_directory(path, base, baselen); qsort(dir, nr_dir, sizeof(struct nond_on_fs *), cmp_name); if (show_others) @@ -681,6 +709,10 @@ int main(int argc, const char **argv) prefix_offset = 0; continue; } + if (!strcmp(arg, "--error-unmatch")) { + error_unmatch = 1; + continue; + } if (*arg == '-') usage(ls_files_usage); break; @@ -692,6 +724,14 @@ int main(int argc, const char **argv) if (pathspec) verify_pathspec(); + /* Treat unmatching pathspec elements as errors */ + if (pathspec && error_unmatch) { + int num; + for (num = 0; pathspec[num]; num++) + ; + ps_matched = xcalloc(1, num); + } + if (show_ignored && !exc_given) { fprintf(stderr, "%s: --ignored needs some exclude pattern\n", argv[0]); @@ -707,5 +747,20 @@ int main(int argc, const char **argv) if (prefix) prune_cache(); show_files(); + + if (ps_matched) { + /* We need to make sure all pathspec matched otherwise + * it is an error. + */ + int num, errors = 0; + for (num = 0; pathspec[num]; num++) { + if (ps_matched[num]) + continue; + error("pathspec '%s' did not match any.", + pathspec[num] + prefix_offset); + } + return errors ? 1 : 0; + } + return 0; }