fixed bug related to the addition of "/*" on sub path param
[git/mingw/4msysgit/wingit-dll.git] / igit-enumfiles.c
blob8d5d4ed76fcc4a353a48405b68682197b38e3f47
1 // igit-enumfiles.c
2 //
4 #include <windows.h>
5 #include "igit.h"
8 // uses the ls-files code
9 #include "builtin-ls-files.c"
12 struct DirStatus
14 // cached last access, to speed up searches (since we get a sorted list from git code)
15 struct DirStatus *pLastAccessedChild;
17 LPCSTR lpszName;
19 struct DirStatus *next;
20 struct DirStatus *children;
21 struct DirStatus *parent;
23 int nStatus;
26 static struct DirStatus l_dirTree;
29 static BOOL l_bNoRecurse;
30 static int l_nMinStatusRelevantForDirs;
31 static BOOL l_bSkipNormalDirs;
32 static int l_nEmptyDirStatus;
33 static BOOL l_bNoRecurseDir;
35 static BOOL l_bFullPath;
36 static char l_sFullPathBuf[2048];
37 static LPSTR l_lpszFileName;
39 static BOOL l_bDirStatus;
40 static int l_nLastStatus;
41 static int l_nEnumeratedCached = 0;
44 static inline char GetStatusChar(int nStatus)
46 switch (nStatus)
48 case WGFS_Normal: return 'N';
49 case WGFS_Modified: return 'M';
50 case WGFS_Staged: return 'S';
51 case WGFS_Added: return 'A';
52 case WGFS_Conflicted: return 'C';
53 case WGFS_Deleted: return 'D';
55 case WGFS_Unversioned: return 'U';
56 case WGFS_Ignored: return 'I';
57 case WGFS_Unknown: return '?';
58 case WGFS_Empty: return 'E';
61 return '?';
66 static BOOL enum_ce_entry(struct cache_entry *ce, struct stat *st)
68 // is this of any use (ce->ce_flags & CE_VALID) ?
70 LPCSTR sFileName;
72 if (!l_bFullPath)
74 sFileName = ce->name + prefix_offset;
76 else
78 strcpy(l_lpszFileName, ce->name);
79 sFileName = l_sFullPathBuf;
82 const int nStage = ce_stage(ce);
84 int nStatus = WGFS_Unknown;
85 if (!st)
86 nStatus = WGFS_Deleted;
87 else if (nStage)
88 nStatus = WGFS_Conflicted;
89 else if ( ce_modified(ce, st, 0) )
90 nStatus = WGFS_Modified;
91 else
92 nStatus = WGFS_Normal;
93 l_nLastStatus = nStatus;
95 // output format: "F status sha1 filename"
97 fputs("F ", stdout);
98 fputc(GetStatusChar(nStatus), stdout);
99 fputc(' ', stdout);
100 fputsha1(ce->sha1, stdout);
101 fputc(' ', stdout);
102 fputs(sFileName, stdout);
103 fputc(0, stdout);
105 l_nEnumeratedCached++;
107 return FALSE;
110 // same as enum except it skips enumeration and just determines status (used for recursive folder status)
111 // returns TRUE if file was processed
112 static BOOL process_ce_entry_status(struct cache_entry *ce, struct stat *st)
114 // is this of any use (ce->ce_flags & CE_VALID) ?
116 /*if (!l_bFullPath)
118 ef.sFileName = ce->name + offset;
120 else
122 strcpy(l_lpszFileName, ce->name);
123 ef.sFileName = l_sFullPathBuf;
126 const int nStage = ce_stage(ce);
128 UINT nStatus = WGFS_Unknown;
129 if (!st)
130 nStatus = WGFS_Deleted;
131 else if (nStage)
132 nStatus = WGFS_Conflicted;
133 else if ( ce_modified(ce, st, 0) )
134 nStatus = WGFS_Modified;
135 else
136 nStatus = WGFS_Normal;
137 l_nLastStatus = nStatus;
139 //ef.nStage = st ? ce_stage(ce) : 0;
140 //ef.nFlags = 0;
141 //ef.sha1 = ce->sha1;
143 return TRUE;
147 static void enum_unversioned(struct dir_entry **files, int nr, BOOL bIgnored)
149 int i;
150 for (i=0; i<nr; i++)
152 struct dir_entry *ent = files[i];
154 // make sure to skip dirs
155 if (ent->name[ent->len-1] == '/')
156 continue;
158 if (!cache_name_is_other(ent->name, ent->len))
159 continue;
161 int len = prefix_len;
163 if (len >= ent->len)
164 die("igit status: internal error - directory entry not superset of prefix");
166 if (pathspec && !pathspec_match(pathspec, ps_matched, ent->name, len))
167 continue;
169 LPCSTR sFileName;
171 if (!l_bFullPath)
173 sFileName = ent->name + prefix_offset;
175 else
177 strcpy(l_lpszFileName, ent->name);
178 sFileName = l_sFullPathBuf;
181 if (bIgnored)
182 fputs("F I 0000000000000000000000000000000000000000 ", stdout);
183 else
184 fputs("F U 0000000000000000000000000000000000000000 ", stdout);
185 fputs(sFileName, stdout);
186 fputc(0, stdout);
191 static inline BOOL enum_dir(struct DirStatus *dir, LPCSTR lpszPathName)
193 if (dir->nStatus == WGFS_Normal && l_bSkipNormalDirs)
194 return FALSE;
196 // output format: "D status pathname"
198 fputs("D ", stdout);
199 fputc(GetStatusChar(dir->nStatus), stdout);
200 fputc(' ', stdout);
201 fputs(lpszPathName, stdout);
202 fputc(0, stdout);
204 return FALSE;
207 static BOOL enum_dirs(struct DirStatus *dir, LPSTR sPathNameBuf)
209 const int len = strlen(dir->lpszName);
210 memcpy(sPathNameBuf, dir->lpszName, len);
211 sPathNameBuf += len;
212 *sPathNameBuf = 0;
214 if ( enum_dir(dir, l_bFullPath ? l_sFullPathBuf : l_sFullPathBuf+prefix_offset) )
215 return TRUE;
217 if (!l_bNoRecurse && dir->children)
219 // recurse
221 *sPathNameBuf++ = '/';
222 *sPathNameBuf = 0;
224 dir = dir->children;
226 while (dir)
228 if ( enum_dirs(dir, sPathNameBuf) )
229 return TRUE;
231 dir = dir->next;
235 return FALSE;
239 static struct DirStatus* GetSubDir(struct DirStatus *dir, LPCSTR lpszName, int nNameLenInclTerminator)
241 // check for cached access
242 if (dir->pLastAccessedChild
243 && !strcmp(dir->pLastAccessedChild->lpszName, lpszName))
245 return dir->pLastAccessedChild;
248 // search children
249 struct DirStatus *p = dir->children;
250 struct DirStatus *last = NULL;
251 while (p)
253 if ( !strcmp(p->lpszName, lpszName) )
254 return (dir->pLastAccessedChild = p);
256 last = p;
257 p = p->next;
260 // dir not accessed before, create new entry
261 // TODO: do more efficient allocator (allocate larger pools, they can still be fire and forget and let our garbage collector clean up)
262 p = dir->pLastAccessedChild = (struct DirStatus*) malloc(sizeof(struct DirStatus) + ((nNameLenInclTerminator+3)&~3));
264 p->pLastAccessedChild = NULL;
265 p->lpszName = (char*)p + sizeof(struct DirStatus);
266 p->next = NULL;
267 p->children = NULL;
268 p->parent = dir;
269 p->nStatus = l_nEmptyDirStatus;
271 // append to list
272 if (dir->children)
273 last->next = p;
274 else
275 dir->children = p;
277 // copy string
278 memcpy((char*)p->lpszName, lpszName, nNameLenInclTerminator);
280 return p;
284 static inline BOOL IsStatusRelevantForDirs(int nStatus)
286 return nStatus >= l_nMinStatusRelevantForDirs && nStatus != WGFS_Deleted;
290 static void update_dirs_rec(LPCSTR lpszFileName, UINT nDirLen, struct cache_entry *ce, BOOL bStatusCached, struct DirStatus *parentDir)
292 const int nDirLen1 = nDirLen+1;
293 char s[nDirLen1];
294 memcpy(s, lpszFileName, nDirLen);
295 s[nDirLen] = 0;
297 struct DirStatus *dir = GetSubDir(parentDir, s, nDirLen1);
298 //ASSERT(dir != NULL);
300 // TODO: if 'conflicted' status is added then need to check for that as highest prio
301 if (dir->nStatus >= WGFS_Modified && l_bNoRecurse)
303 // no further processing needed
304 return;
307 // process next subdir in lpszFileName
309 lpszFileName += nDirLen1;
311 LPCSTR p = strchr(lpszFileName, '/');
312 if (!p)
314 // no more dirs in pathname (ie we are in the dir the file is located)
316 if (!bStatusCached)
318 // file status not determined yet, do it now
319 struct stat st;
320 int err = lstat(ce->name, &st);
321 if (!process_ce_entry_status(ce, err ? NULL : &st) || !IsStatusRelevantForDirs(l_nLastStatus))
322 return;
324 const int nFileStatus = l_nLastStatus;
326 if (nFileStatus > dir->nStatus)
328 // update status on dir and all parents
331 if (nFileStatus > dir->nStatus)
332 dir->nStatus = nFileStatus;
334 while ( (dir = dir->parent) );
337 else if (lpszFileName != p) // quick check to make sure we're not left with a "/" filename
339 update_dirs_rec(lpszFileName, (UINT)(p-lpszFileName), ce, bStatusCached, dir);
343 static void update_dirs(struct cache_entry *ce, int nPathNameOffset, BOOL bStatusCached)
345 // filename relative to enumerated path
346 LPCSTR lpszFileName = ce->name + nPathNameOffset;
348 LPCSTR p = strchr(lpszFileName, '/');
349 if (p <= lpszFileName)
351 // file is not in sub-dir
353 if (!bStatusCached)
355 // file status not determined yet, do it now
356 struct stat st;
357 int err = lstat(ce->name, &st);
358 if (!process_ce_entry_status(ce, err ? NULL : &st) || !IsStatusRelevantForDirs(l_nLastStatus))
359 return;
361 const int nFileStatus = l_nLastStatus;
363 if (nFileStatus > l_dirTree.nStatus)
364 l_dirTree.nStatus = nFileStatus;
366 return;
369 if (!l_bNoRecurseDir)
371 update_dirs_rec(lpszFileName, (UINT)(p-lpszFileName), ce, bStatusCached, &l_dirTree);
376 static inline BOOL is_subpath(const char *sPath, int nPathLen, const char *sFile)
378 return strchr(sFile + nPathLen, '/') != NULL;
381 static BOOL is_dir(const char *sProjectPath, const char *sSubPath)
383 char s[2048];
385 strcpy(s, sProjectPath);
386 // backslashify
387 LPSTR q = s;
388 while (*q)
390 if (*q == '/')
391 *q = '\\';
392 q++;
394 // make sure it ends with a slash
395 if (q[-1] != '\\')
396 *q++ = '\\';
397 strcpy(q, sSubPath);
398 // backslashify sub-path
399 while (*q)
401 if (*q == '/')
402 *q = '\\';
403 q++;
406 struct stat st;
407 int err = lstat(s, &st);
409 return (!err && S_ISDIR(st.st_mode));
412 static inline BOOL is_ce_name_eq(struct cache_entry *ce1, struct cache_entry *ce2)
414 const size_t len1 = ce1->ce_flags & CE_NAMEMASK;
415 const size_t len2 = ce2->ce_flags & CE_NAMEMASK;
417 return (len1 == len2) ? !strcmp(ce1->name, ce2->name) : FALSE;
421 BOOL ig_enum_files(const char *pszProjectPath, const char *pszSubPath, const char *prefix, unsigned int nFlags)
423 // reset all local vars of builtin-ls-files.c to default
424 abbrev = 0;
425 show_deleted = 0;
426 show_cached = 0;
427 show_others = 0;
428 show_stage = 0;
429 show_unmerged = 0;
430 show_modified = 0;
431 show_killed = 0;
432 show_valid_bit = 0;
433 line_terminator = '\n';
434 prefix_len = 0;
435 prefix_offset = 0;
436 pathspec = 0;
437 error_unmatch = 0;
438 ps_matched = 0;
439 with_tree = 0;
440 tag_cached = "";
441 tag_unmerged = "";
442 tag_removed = "";
443 tag_other = "";
444 tag_killed = "";
445 tag_modified = "";
447 const BOOL bSubDir = pszSubPath && is_dir(pszProjectPath, pszSubPath);
449 LPCSTR pszSubPathSpec = pszSubPath;
450 if (bSubDir && !(nFlags & WGEFF_SingleFile))
452 int len = strlen(pszSubPath);
453 char *s = (char*)malloc(len+3);
454 strcpy(s, pszSubPath);
455 strcpy(s+len, "/*");
456 pszSubPathSpec = s;
459 int i;
460 //int exc_given = 0, require_work_tree = 0;
461 struct dir_struct _dir;
463 memset(&_dir, 0, sizeof(_dir));
465 memset(&l_dirTree, 0, sizeof(l_dirTree));
466 l_dirTree.nStatus = WGFS_Normal; // root dir is always at least WGFS_Normal even if empty
467 if (pszSubPath && !(nFlags & WGEFF_EmptyAsNormal))
468 l_dirTree.nStatus = WGFS_Empty;
470 // NOTE: to force names to be relative to project root dir (no mater what current dir is) set prefix_offset to 0
471 if (prefix)
472 prefix_offset = strlen(prefix);
473 git_config(git_default_config, NULL);
475 struct dir_struct *dir = &_dir;
477 const char *argv[2];
478 argv[0] = pszSubPathSpec;
479 argv[1] = NULL;
481 if (/*require_work_tree &&*/ !is_inside_work_tree())
482 setup_work_tree();
484 pathspec = get_pathspec(prefix, argv);
486 // Verify that the pathspec matches the prefix
487 if (pathspec)
488 prefix = verify_pathspec(prefix);
490 // Treat unmatching pathspec elements as errors
491 if (pathspec && error_unmatch)
493 int num;
494 for (num = 0; pathspec[num]; num++)
496 ps_matched = xcalloc(1, num);
499 // vars used for path recursion check
500 int pathspec_len = 0;
501 if (pathspec && *pathspec)
503 // calc length of pathspec plus 1 for a / (unless it already ends with a slash)
504 pathspec_len = strlen(*pathspec);
505 if ((*pathspec)[pathspec_len-1] == '*')
506 pathspec_len--;
507 if ((*pathspec)[pathspec_len-1] != '/')
508 pathspec_len++;
510 const char *refpath = (pathspec && *pathspec) ? *pathspec : "";
513 // configure
516 l_bNoRecurseDir = FALSE;
518 BOOL single_dir = (nFlags & WGEFF_SingleFile) && (!pszSubPath || bSubDir);
519 // adjust other flags for best performance / correct results when WGEFF_SingleFile is set
520 if (single_dir && (nFlags & WGEFF_NoRecurse))
521 l_bNoRecurseDir = TRUE;
522 if (nFlags & WGEFF_SingleFile)
524 nFlags |= WGEFF_NoRecurse;
525 if (!single_dir)
526 nFlags &= ~(WGEFF_DirStatusAll|WGEFF_DirStatusDelta);
528 if (single_dir)
530 nFlags = (nFlags & ~WGEFF_DirStatusAll) | WGEFF_DirStatusDelta;
532 if ( !(nFlags & WGEFF_EmptyAsNormal) )
533 l_dirTree.nStatus = WGFS_Empty;
536 BOOL no_recurse = nFlags & WGEFF_NoRecurse;
537 l_bNoRecurse = no_recurse;
538 l_bFullPath = nFlags & WGEFF_FullPath;
539 l_bDirStatus = nFlags & (WGEFF_DirStatusDelta|WGEFF_DirStatusAll);
541 // when all dirs should be enumerated we need IsStatusRelevantForDirs to report files of normal status as relevant
542 // otherwise only above normal are considered, which is slightly more efficient
543 l_nMinStatusRelevantForDirs = (nFlags & WGEFF_DirStatusAll) ? WGFS_Normal : (WGFS_Normal+1);
545 // initial status of dirs
546 l_nEmptyDirStatus = (nFlags & WGEFF_EmptyAsNormal) ? WGFS_Normal : WGFS_Empty;
548 l_bSkipNormalDirs = ((nFlags & (WGEFF_DirStatusDelta|WGEFF_DirStatusAll)) == WGEFF_DirStatusDelta);
550 *l_sFullPathBuf = 0;
551 l_lpszFileName = NULL;
552 if (l_bFullPath)
554 strcpy(l_sFullPathBuf, pszProjectPath);
555 // slashify
556 LPSTR q = l_sFullPathBuf;
557 while (*q)
559 if (*q == '\\')
560 *q = '/';
561 q++;
563 // make sure it ends with a slash
564 if (q[-1] != '/')
566 *q++ = '/';
567 *q = 0;
569 // save pointer to where file paths, with project-relative names, can be concatenated
570 l_lpszFileName = q;
573 // shouldn't have any effect but set them to reflect what we want listed
574 show_cached = 1;
575 show_modified = 1;
576 show_deleted = 1;
577 show_unmerged = 1;
579 read_cache();
580 if (prefix)
581 prune_cache(prefix);
583 //if (pathspec && *pathspec) OutputDebugString(*pathspec);OutputDebugString(" (1)\r\n");
584 //if (prefix) OutputDebugString(prefix);OutputDebugString(" (2)\r\n");
587 // enum files
590 for (i=0; i<active_nr; i++)
592 struct cache_entry *ce = active_cache[i];
593 struct stat st;
594 int err;
596 int dtype = ce_to_dtype(ce);
598 if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
599 continue;
600 if (ce->ce_flags & CE_UPDATE)
601 continue;
603 // skip file if not inside specified sub-path
604 // this test was originally done in enum_ce_entry but in order to avoid unecessery lstat calls it was moved
605 if (prefix_len >= ce_namelen(ce))
606 die("git ls-files: internal error - cache entry not superset of prefix");
607 if (pathspec && !pathspec_match(pathspec, ps_matched, ce->name, prefix_len))
608 continue;
610 if (single_dir || (no_recurse && is_subpath(refpath, pathspec_len, ce->name)))
612 if (l_bDirStatus)
613 // this file would normally be skipped, but in order to determine correct dir status we need to process it
614 update_dirs(ce, pathspec_len, FALSE);
616 continue;
619 err = lstat(ce->name, &st);
621 if ( enum_ce_entry(ce, err ? NULL : &st) )
622 return TRUE;
624 // normally (always?) conflicted/unmerged files will have 3 entries in a row (one in stage 1, one in 2 and one in 3)
625 // skip redundant entries here
626 if ( ce_stage(ce) )
628 int j;
630 for (j=i+1; j<active_nr; j++)
632 struct cache_entry *nextce = active_cache[j];
634 if ( !is_ce_name_eq(ce, nextce) )
635 break;
637 i = j;
641 if (l_bDirStatus && IsStatusRelevantForDirs(l_nLastStatus))
642 update_dirs(ce, pathspec_len, TRUE);
645 // enumerate unversioned files
646 if ( !(nFlags & WGEFF_SingleFile) )
648 const char *path = ".", *base = "";
649 int baselen = prefix_len;
651 if (baselen)
652 path = base = prefix;
654 setup_standard_excludes(dir);
655 dir->collect_ignored = 1;
656 dir->show_ignored = 0;
657 dir->show_other_directories = 0;
658 dir->hide_empty_directories = 0;
659 dir->collect_all_ignored = 1;
660 dir->no_recurse_readdir = no_recurse ? 1 : 0;
661 read_directory(dir, path, base, baselen, pathspec);
663 enum_unversioned(dir->entries, dir->nr, FALSE);
664 enum_unversioned(dir->ignored, dir->ignored_nr, TRUE);
666 else if (!single_dir && !l_nEnumeratedCached)
668 // get status of a single unversioned file
670 setup_standard_excludes(dir);
672 LPCSTR sFileName;
674 if (!l_bFullPath)
676 sFileName = pszSubPath + prefix_offset;
678 else
680 strcpy(l_lpszFileName, pszSubPath);
681 sFileName = l_sFullPathBuf;
684 int dtype = DT_REG;
685 if ( excluded(dir, pszSubPath, &dtype) )
686 fputs("F I 0000000000000000000000000000000000000000 ", stdout);
687 else
688 fputs("F U 0000000000000000000000000000000000000000 ", stdout);
689 fputs(sFileName, stdout);
690 fputc(0, stdout);
693 if (l_bDirStatus)
695 // enumerate dirs
697 LPCSTR lpszRootDir="/";
698 if (l_bFullPath)
700 lpszRootDir = l_sFullPathBuf;
701 if (pathspec_len)
703 strcpy(l_lpszFileName, *pathspec);
704 l_lpszFileName += pathspec_len;
707 *l_lpszFileName = 0;
708 // remove trailng slash
709 l_lpszFileName[-1] = 0;
711 else if (pathspec_len)
713 lpszRootDir = *pathspec;
715 strcpy(l_sFullPathBuf, *pathspec);
716 l_sFullPathBuf[pathspec_len-1] = '/';
717 l_sFullPathBuf[pathspec_len] = 0;
718 l_lpszFileName = l_sFullPathBuf;
720 else
722 lpszRootDir = ".";
724 l_lpszFileName = l_sFullPathBuf;
727 if (single_dir)
729 // enumerate single dir
730 l_bSkipNormalDirs = FALSE;
731 enum_dir(&l_dirTree, lpszRootDir);
733 else if (!enum_dir(&l_dirTree, lpszRootDir) && l_dirTree.children)
735 if (l_bFullPath)
736 // re-add trailing slash
737 l_lpszFileName[-1] = '/';
739 struct DirStatus *p = l_dirTree.children;
743 if ( enum_dirs(p, l_lpszFileName) )
744 break;
746 while ( (p = p->next) );
750 return TRUE;
754 #if 0
757 * This merges the file listing in the directory cache index
758 * with the actual working directory list, and shows different
759 * combinations of the two.
761 * Copyright (C) Linus Torvalds, 2005
763 #include "cache.h"
764 #include "quote.h"
765 #include "dir.h"
766 #include "builtin.h"
767 #include "tree.h"
769 static int abbrev;
770 static int show_deleted;
771 static int show_cached;
772 static int show_others;
773 static int show_stage;
774 static int show_unmerged;
775 static int show_modified;
776 static int show_killed;
777 static int show_valid_bit;
778 static int line_terminator = '\n';
780 static int prefix_len;
781 static int prefix_offset;
782 static const char **pathspec;
783 static int error_unmatch;
784 static char *ps_matched;
785 static const char *with_tree;
787 static const char *tag_cached = "";
788 static const char *tag_unmerged = "";
789 static const char *tag_removed = "";
790 static const char *tag_other = "";
791 static const char *tag_killed = "";
792 static const char *tag_modified = "";
796 * Match a pathspec against a filename. The first "skiplen" characters
797 * are the common prefix
799 int pathspec_match(const char **spec, char *ps_matched,
800 const char *filename, int skiplen)
802 const char *m;
804 while ((m = *spec++) != NULL) {
805 int matchlen = strlen(m + skiplen);
807 if (!matchlen)
808 goto matched;
809 if (!strncmp(m + skiplen, filename + skiplen, matchlen)) {
810 if (m[skiplen + matchlen - 1] == '/')
811 goto matched;
812 switch (filename[skiplen + matchlen]) {
813 case '/': case '\0':
814 goto matched;
817 if (!fnmatch(m + skiplen, filename + skiplen, 0))
818 goto matched;
819 if (ps_matched)
820 ps_matched++;
821 continue;
822 matched:
823 if (ps_matched)
824 *ps_matched = 1;
825 return 1;
827 return 0;
830 static void show_dir_entry(const char *tag, struct dir_entry *ent)
832 int len = prefix_len;
833 int offset = prefix_offset;
835 if (len >= ent->len)
836 die("git ls-files: internal error - directory entry not superset of prefix");
838 if (pathspec && !pathspec_match(pathspec, ps_matched, ent->name, len))
839 return;
841 fputs(tag, stdout);
842 write_name_quoted(ent->name + offset, stdout, line_terminator);
845 static void show_other_files(struct dir_struct *dir)
847 int i;
849 for (i = 0; i < dir->nr; i++) {
850 struct dir_entry *ent = dir->entries[i];
851 if (!cache_name_is_other(ent->name, ent->len))
852 continue;
853 show_dir_entry(tag_other, ent);
857 static void show_killed_files(struct dir_struct *dir)
859 int i;
860 for (i = 0; i < dir->nr; i++) {
861 struct dir_entry *ent = dir->entries[i];
862 char *cp, *sp;
863 int pos, len, killed = 0;
865 for (cp = ent->name; cp - ent->name < ent->len; cp = sp + 1) {
866 sp = strchr(cp, '/');
867 if (!sp) {
868 /* If ent->name is prefix of an entry in the
869 * cache, it will be killed.
871 pos = cache_name_pos(ent->name, ent->len);
872 if (0 <= pos)
873 die("bug in show-killed-files");
874 pos = -pos - 1;
875 while (pos < active_nr &&
876 ce_stage(active_cache[pos]))
877 pos++; /* skip unmerged */
878 if (active_nr <= pos)
879 break;
880 /* pos points at a name immediately after
881 * ent->name in the cache. Does it expect
882 * ent->name to be a directory?
884 len = ce_namelen(active_cache[pos]);
885 if ((ent->len < len) &&
886 !strncmp(active_cache[pos]->name,
887 ent->name, ent->len) &&
888 active_cache[pos]->name[ent->len] == '/')
889 killed = 1;
890 break;
892 if (0 <= cache_name_pos(ent->name, sp - ent->name)) {
893 /* If any of the leading directories in
894 * ent->name is registered in the cache,
895 * ent->name will be killed.
897 killed = 1;
898 break;
901 if (killed)
902 show_dir_entry(tag_killed, dir->entries[i]);
906 static void show_ce_entry(const char *tag, struct cache_entry *ce)
908 int len = prefix_len;
909 int offset = prefix_offset;
911 if (len >= ce_namelen(ce))
912 die("git ls-files: internal error - cache entry not superset of prefix");
914 if (pathspec && !pathspec_match(pathspec, ps_matched, ce->name, len))
915 return;
917 if (tag && *tag && show_valid_bit &&
918 (ce->ce_flags & CE_VALID)) {
919 static char alttag[4];
920 memcpy(alttag, tag, 3);
921 if (isalpha(tag[0]))
922 alttag[0] = tolower(tag[0]);
923 else if (tag[0] == '?')
924 alttag[0] = '!';
925 else {
926 alttag[0] = 'v';
927 alttag[1] = tag[0];
928 alttag[2] = ' ';
929 alttag[3] = 0;
931 tag = alttag;
934 if (!show_stage) {
935 fputs(tag, stdout);
936 } else {
937 printf("%s%06o %s %d\t",
938 tag,
939 ce->ce_mode,
940 abbrev ? find_unique_abbrev(ce->sha1,abbrev)
941 : sha1_to_hex(ce->sha1),
942 ce_stage(ce));
944 write_name_quoted(ce->name + offset, stdout, line_terminator);
947 static void show_files(struct dir_struct *dir, const char *prefix)
949 int i;
951 /* For cached/deleted files we don't need to even do the readdir */
952 if (show_others || show_killed) {
953 const char *path = ".", *base = "";
954 int baselen = prefix_len;
956 if (baselen)
957 path = base = prefix;
958 read_directory(dir, path, base, baselen, pathspec);
959 if (show_others)
960 show_other_files(dir);
961 if (show_killed)
962 show_killed_files(dir);
964 if (show_cached | show_stage) {
965 for (i = 0; i < active_nr; i++) {
966 struct cache_entry *ce = active_cache[i];
967 int dtype = ce_to_dtype(ce);
968 if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
969 continue;
970 if (show_unmerged && !ce_stage(ce))
971 continue;
972 if (ce->ce_flags & CE_UPDATE)
973 continue;
974 show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);
977 if (show_deleted | show_modified) {
978 for (i = 0; i < active_nr; i++) {
979 struct cache_entry *ce = active_cache[i];
980 struct stat st;
981 int err;
982 int dtype = ce_to_dtype(ce);
983 if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
984 continue;
985 if (ce->ce_flags & CE_UPDATE)
986 continue;
987 err = lstat(ce->name, &st);
988 if (show_deleted && err)
989 show_ce_entry(tag_removed, ce);
990 if (show_modified && ce_modified(ce, &st, 0))
991 show_ce_entry(tag_modified, ce);
997 * Prune the index to only contain stuff starting with "prefix"
999 static void prune_cache(const char *prefix)
1001 int pos = cache_name_pos(prefix, prefix_len);
1002 unsigned int first, last;
1004 if (pos < 0)
1005 pos = -pos-1;
1006 memmove(active_cache, active_cache + pos,
1007 (active_nr - pos) * sizeof(struct cache_entry *));
1008 active_nr -= pos;
1009 first = 0;
1010 last = active_nr;
1011 while (last > first) {
1012 int next = (last + first) >> 1;
1013 struct cache_entry *ce = active_cache[next];
1014 if (!strncmp(ce->name, prefix, prefix_len)) {
1015 first = next+1;
1016 continue;
1018 last = next;
1020 active_nr = last;
1023 static const char *verify_pathspec(const char *prefix)
1025 const char **p, *n, *prev;
1026 unsigned long max;
1028 prev = NULL;
1029 max = PATH_MAX;
1030 for (p = pathspec; (n = *p) != NULL; p++) {
1031 int i, len = 0;
1032 for (i = 0; i < max; i++) {
1033 char c = n[i];
1034 if (prev && prev[i] != c)
1035 break;
1036 if (!c || c == '*' || c == '?')
1037 break;
1038 if (c == '/')
1039 len = i+1;
1041 prev = n;
1042 if (len < max) {
1043 max = len;
1044 if (!max)
1045 break;
1049 if (prefix_offset > max || memcmp(prev, prefix, prefix_offset))
1050 die("git ls-files: cannot generate relative filenames containing '..'");
1052 prefix_len = max;
1053 return max ? xmemdupz(prev, max) : NULL;
1057 * Read the tree specified with --with-tree option
1058 * (typically, HEAD) into stage #1 and then
1059 * squash them down to stage #0. This is used for
1060 * --error-unmatch to list and check the path patterns
1061 * that were given from the command line. We are not
1062 * going to write this index out.
1064 void overlay_tree_on_cache(const char *tree_name, const char *prefix)
1066 struct tree *tree;
1067 unsigned char sha1[20];
1068 const char **match;
1069 struct cache_entry *last_stage0 = NULL;
1070 int i;
1072 if (get_sha1(tree_name, sha1))
1073 die("tree-ish %s not found.", tree_name);
1074 tree = parse_tree_indirect(sha1);
1075 if (!tree)
1076 die("bad tree-ish %s", tree_name);
1078 /* Hoist the unmerged entries up to stage #3 to make room */
1079 for (i = 0; i < active_nr; i++) {
1080 struct cache_entry *ce = active_cache[i];
1081 if (!ce_stage(ce))
1082 continue;
1083 ce->ce_flags |= CE_STAGEMASK;
1086 if (prefix) {
1087 static const char *(matchbuf[2]);
1088 matchbuf[0] = prefix;
1089 matchbuf[1] = NULL;
1090 match = matchbuf;
1091 } else
1092 match = NULL;
1093 if (read_tree(tree, 1, match))
1094 die("unable to read tree entries %s", tree_name);
1096 for (i = 0; i < active_nr; i++) {
1097 struct cache_entry *ce = active_cache[i];
1098 switch (ce_stage(ce)) {
1099 case 0:
1100 last_stage0 = ce;
1101 /* fallthru */
1102 default:
1103 continue;
1104 case 1:
1106 * If there is stage #0 entry for this, we do not
1107 * need to show it. We use CE_UPDATE bit to mark
1108 * such an entry.
1110 if (last_stage0 &&
1111 !strcmp(last_stage0->name, ce->name))
1112 ce->ce_flags |= CE_UPDATE;
1117 int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset)
1120 * Make sure all pathspec matched; otherwise it is an error.
1122 int num, errors = 0;
1123 for (num = 0; pathspec[num]; num++) {
1124 int other, found_dup;
1126 if (ps_matched[num])
1127 continue;
1129 * The caller might have fed identical pathspec
1130 * twice. Do not barf on such a mistake.
1132 for (found_dup = other = 0;
1133 !found_dup && pathspec[other];
1134 other++) {
1135 if (other == num || !ps_matched[other])
1136 continue;
1137 if (!strcmp(pathspec[other], pathspec[num]))
1139 * Ok, we have a match already.
1141 found_dup = 1;
1143 if (found_dup)
1144 continue;
1146 error("pathspec '%s' did not match any file(s) known to git.",
1147 pathspec[num] + prefix_offset);
1148 errors++;
1150 return errors;
1153 static const char ls_files_usage[] =
1154 "git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
1155 "[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
1156 "[ --exclude-per-directory=<filename> ] [--exclude-standard] "
1157 "[--full-name] [--abbrev] [--] [<file>]*";
1159 int cmd_ls_files(int argc, const char **argv, const char *prefix)
1161 int i;
1162 int exc_given = 0, require_work_tree = 0;
1163 struct dir_struct dir;
1165 memset(&dir, 0, sizeof(dir));
1166 if (prefix)
1167 prefix_offset = strlen(prefix);
1168 git_config(git_default_config, NULL);
1170 for (i = 1; i < argc; i++) {
1171 const char *arg = argv[i];
1173 if (!strcmp(arg, "--")) {
1174 i++;
1175 break;
1177 if (!strcmp(arg, "-z")) {
1178 line_terminator = 0;
1179 continue;
1181 if (!strcmp(arg, "-t") || !strcmp(arg, "-v")) {
1182 tag_cached = "H ";
1183 tag_unmerged = "M ";
1184 tag_removed = "R ";
1185 tag_modified = "C ";
1186 tag_other = "? ";
1187 tag_killed = "K ";
1188 if (arg[1] == 'v')
1189 show_valid_bit = 1;
1190 continue;
1192 if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) {
1193 show_cached = 1;
1194 continue;
1196 if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
1197 show_deleted = 1;
1198 continue;
1200 if (!strcmp(arg, "-m") || !strcmp(arg, "--modified")) {
1201 show_modified = 1;
1202 require_work_tree = 1;
1203 continue;
1205 if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) {
1206 show_others = 1;
1207 require_work_tree = 1;
1208 continue;
1210 if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) {
1211 dir.show_ignored = 1;
1212 require_work_tree = 1;
1213 continue;
1215 if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) {
1216 show_stage = 1;
1217 continue;
1219 if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
1220 show_killed = 1;
1221 require_work_tree = 1;
1222 continue;
1224 if (!strcmp(arg, "--directory")) {
1225 dir.show_other_directories = 1;
1226 continue;
1228 if (!strcmp(arg, "--no-empty-directory")) {
1229 dir.hide_empty_directories = 1;
1230 continue;
1232 if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
1233 /* There's no point in showing unmerged unless
1234 * you also show the stage information.
1236 show_stage = 1;
1237 show_unmerged = 1;
1238 continue;
1240 if (!strcmp(arg, "-x") && i+1 < argc) {
1241 exc_given = 1;
1242 add_exclude(argv[++i], "", 0, &dir.exclude_list[EXC_CMDL]);
1243 continue;
1245 if (!prefixcmp(arg, "--exclude=")) {
1246 exc_given = 1;
1247 add_exclude(arg+10, "", 0, &dir.exclude_list[EXC_CMDL]);
1248 continue;
1250 if (!strcmp(arg, "-X") && i+1 < argc) {
1251 exc_given = 1;
1252 add_excludes_from_file(&dir, argv[++i]);
1253 continue;
1255 if (!prefixcmp(arg, "--exclude-from=")) {
1256 exc_given = 1;
1257 add_excludes_from_file(&dir, arg+15);
1258 continue;
1260 if (!prefixcmp(arg, "--exclude-per-directory=")) {
1261 exc_given = 1;
1262 dir.exclude_per_dir = arg + 24;
1263 continue;
1265 if (!strcmp(arg, "--exclude-standard")) {
1266 exc_given = 1;
1267 setup_standard_excludes(&dir);
1268 continue;
1270 if (!strcmp(arg, "--full-name")) {
1271 prefix_offset = 0;
1272 continue;
1274 if (!strcmp(arg, "--error-unmatch")) {
1275 error_unmatch = 1;
1276 continue;
1278 if (!prefixcmp(arg, "--with-tree=")) {
1279 with_tree = arg + 12;
1280 continue;
1282 if (!prefixcmp(arg, "--abbrev=")) {
1283 abbrev = strtoul(arg+9, NULL, 10);
1284 if (abbrev && abbrev < MINIMUM_ABBREV)
1285 abbrev = MINIMUM_ABBREV;
1286 else if (abbrev > 40)
1287 abbrev = 40;
1288 continue;
1290 if (!strcmp(arg, "--abbrev")) {
1291 abbrev = DEFAULT_ABBREV;
1292 continue;
1294 if (*arg == '-')
1295 usage(ls_files_usage);
1296 break;
1299 if (require_work_tree && !is_inside_work_tree())
1300 setup_work_tree();
1302 pathspec = get_pathspec(prefix, argv + i);
1304 /* Verify that the pathspec matches the prefix */
1305 if (pathspec)
1306 prefix = verify_pathspec(prefix);
1308 /* Treat unmatching pathspec elements as errors */
1309 if (pathspec && error_unmatch) {
1310 int num;
1311 for (num = 0; pathspec[num]; num++)
1313 ps_matched = xcalloc(1, num);
1316 if (dir.show_ignored && !exc_given) {
1317 fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
1318 argv[0]);
1319 exit(1);
1322 /* With no flags, we default to showing the cached files */
1323 if (!(show_stage | show_deleted | show_others | show_unmerged |
1324 show_killed | show_modified))
1325 show_cached = 1;
1327 read_cache();
1328 if (prefix)
1329 prune_cache(prefix);
1330 if (with_tree) {
1332 * Basic sanity check; show-stages and show-unmerged
1333 * would not make any sense with this option.
1335 if (show_stage || show_unmerged)
1336 die("ls-files --with-tree is incompatible with -s or -u");
1337 overlay_tree_on_cache(with_tree, prefix);
1339 show_files(&dir, prefix);
1341 if (ps_matched) {
1342 int bad;
1343 bad = report_path_error(ps_matched, pathspec, prefix_offset);
1344 if (bad)
1345 fprintf(stderr, "Did you forget to 'git add'?\n");
1347 return bad ? 1 : 0;
1350 return 0;
1353 #endif