+/*
+ * 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)
+{
+ const char *m;
+
+ while ((m = *spec++) != NULL) {
+ int matchlen = strlen(m + len);
+
+ if (!matchlen)
+ return 1;
+ if (!strncmp(m + len, filename + len, matchlen)) {
+ if (m[len + matchlen - 1] == '/')
+ return 1;
+ switch (filename[len + matchlen]) {
+ case '/': case '\0':
+ return 1;
+ }
+ }
+ if (!fnmatch(m + len, filename + len, 0))
+ return 1;
+ }
+ return 0;
+}
+
+static void show_dir_entry(const char *tag, struct nond_on_fs *ent)
+{
+ int len = prefix_len;
+ int offset = prefix_offset;
+
+ if (len >= ent->len)
+ die("git-ls-files: internal error - directory entry not superset of prefix");
+
+ if (pathspec && !match(pathspec, ent->name, len))
+ return;
+
+ fputs(tag, stdout);
+ write_name_quoted("", 0, ent->name + offset, line_terminator, stdout);
+ putchar(line_terminator);
+}
+
+static void show_other_files(void)
+{
+ int i;
+ for (i = 0; i < nr_dir; i++) {
+ /* We should not have a matching entry, but we
+ * may have an unmerged entry for this path.
+ */
+ struct nond_on_fs *ent = dir[i];
+ int pos = cache_name_pos(ent->name, ent->len);
+ struct cache_entry *ce;
+ if (0 <= pos)
+ die("bug in show-other-files");
+ pos = -pos - 1;
+ if (pos < active_nr) {
+ ce = active_cache[pos];
+ if (ce_namelen(ce) == ent->len &&
+ !memcmp(ce->name, ent->name, ent->len))
+ continue; /* Yup, this one exists unmerged */
+ }
+ show_dir_entry(tag_other, ent);
+ }
+}
+