changed added/conflicted checking order
[git/mingw/4msysgit/wingit-dll.git] / igit-enumfiles.c
blobdaf55054fc32504146037e3e922195cb9ea06e92
1 // igit-enumfiles.c
2 //
4 #include <windows.h>
5 #include "igit.h"
7 #include "cache.h"
8 #include "commit.h"
9 #include "diff.h"
10 #include "diffcore.h"
11 #include "revision.h"
12 #include "cache-tree.h"
13 #include "unpack-trees.h"
14 #include "reflog-walk.h"
17 // uses the ls-files code
18 #include "builtin-ls-files.c"
21 // custom cache entry flags (just to make sure that no git functions get confused)
22 #define CE_IG_ADDED 0x2000000
23 #define CE_IG_DELETED 0x4000000
24 #define CE_IG_STAGED 0x8000000
27 struct DirStatus
29 // cached last access, to speed up searches (since we get a sorted list from git code)
30 struct DirStatus *pLastAccessedChild;
32 LPCSTR lpszName;
34 struct DirStatus *next;
35 struct DirStatus *children;
36 struct DirStatus *parent;
38 int nStatus;
39 BOOL bExplicitlyIgnored;
42 static struct DirStatus l_dirTree;
45 struct EntryRef
47 struct cache_entry *ce;
48 struct EntryRef *next;
51 static struct EntryRef *l_delQueue = NULL;
54 static BOOL l_bNoRecurse;
55 static int l_nMinStatusRelevantForDirs;
56 static BOOL l_bSkipNormalDirs;
57 static int l_nEmptyDirStatus;
58 static BOOL l_bNoRecurseDir;
60 static BOOL l_bFullPath;
61 static char l_sFullPathBuf[2048];
62 static LPSTR l_lpszFileName;
64 static BOOL l_bDirStatus;
65 static int l_nLastStatus;
66 static int l_nEnumeratedCached = 0;
68 static BOOL l_bHasHistory = FALSE;
71 static inline char GetStatusChar(int nStatus)
73 switch (nStatus)
75 case WGFS_Normal: return 'N';
76 case WGFS_Modified: return 'M';
77 case WGFS_Staged: return 'S';
78 case WGFS_Added: return 'A';
79 case WGFS_Conflicted: return 'C';
80 case WGFS_Deleted: return 'D';
82 case WGFS_Unversioned: return 'U';
83 case WGFS_Ignored: return 'I';
84 case WGFS_Unknown: return '?';
85 case WGFS_Empty: return 'E';
88 return '?';
92 static inline void queue_deleted(struct cache_entry *ce)
94 struct EntryRef *p = (struct EntryRef*) malloc( sizeof(struct EntryRef) );
96 p->ce = ce;
98 p->next = l_delQueue;
99 l_delQueue = p;
103 static BOOL enum_ce_entry(struct cache_entry *ce, struct stat *st)
105 // is this of any use (ce->ce_flags & CE_VALID) ?
107 LPCSTR sFileName;
109 if (!l_bFullPath)
111 sFileName = ce->name + prefix_offset;
113 else
115 strcpy(l_lpszFileName, ce->name);
116 sFileName = l_sFullPathBuf;
119 const int nStage = ce_stage(ce);
121 int nStatus = WGFS_Unknown;
122 if (!st || (ce->ce_flags & CE_IG_DELETED))
123 nStatus = WGFS_Deleted;
124 else if (nStage)
125 nStatus = WGFS_Conflicted;
126 else if (ce->ce_flags & CE_IG_ADDED)
127 nStatus = WGFS_Added;
128 else if ( ce_modified(ce, st, 0) )
129 nStatus = WGFS_Modified;
130 else if (ce->ce_flags & CE_IG_STAGED)
131 nStatus = WGFS_Staged;
132 else if (!l_bHasHistory)
133 nStatus = WGFS_Added;
134 else
135 nStatus = WGFS_Normal;
136 l_nLastStatus = nStatus;
138 // output format: "F status sha1 filename"
140 fputs("F ", stdout);
141 fputc(GetStatusChar(nStatus), stdout);
142 fputc(' ', stdout);
143 fputsha1(ce->sha1, stdout);
144 fputc(' ', stdout);
145 fputs(sFileName, stdout);
146 fputc(0, stdout);
148 l_nEnumeratedCached++;
150 return FALSE;
153 // same as enum except it skips enumeration and just determines status (used for recursive folder status)
154 // returns TRUE if file was processed
155 static BOOL process_ce_entry_status(struct cache_entry *ce, struct stat *st)
157 // is this of any use (ce->ce_flags & CE_VALID) ?
159 /*if (!l_bFullPath)
161 ef.sFileName = ce->name + offset;
163 else
165 strcpy(l_lpszFileName, ce->name);
166 ef.sFileName = l_sFullPathBuf;
169 const int nStage = ce_stage(ce);
171 UINT nStatus = WGFS_Unknown;
172 if (!st || (ce->ce_flags & CE_IG_DELETED))
173 nStatus = WGFS_Deleted;
174 else if (nStage)
175 nStatus = WGFS_Conflicted;
176 else if (ce->ce_flags & CE_IG_ADDED)
177 nStatus = WGFS_Added;
178 else if ( ce_modified(ce, st, 0) )
179 nStatus = WGFS_Modified;
180 else if (ce->ce_flags & CE_IG_STAGED)
181 nStatus = WGFS_Staged;
182 else if (!l_bHasHistory)
183 nStatus = WGFS_Added;
184 else
185 nStatus = WGFS_Normal;
186 l_nLastStatus = nStatus;
188 //ef.nStage = st ? ce_stage(ce) : 0;
189 //ef.nFlags = 0;
190 //ef.sha1 = ce->sha1;
192 return TRUE;
196 static void update_dirs_unversioned(struct dir_entry *ce, int nPathNameOffset);
198 static void enum_unversioned(struct dir_entry **files, int nr, BOOL bIgnored)
200 int i;
201 for (i=0; i<nr; i++)
203 struct dir_entry *ent = files[i];
205 if (ent->name[ent->len-1] != '/' && !cache_name_is_other(ent->name, ent->len))
206 continue;
208 int len = prefix_len;
210 if (len >= ent->len)
211 die("igit status: internal error - directory entry not superset of prefix");
213 if (pathspec && !pathspec_match(pathspec, ps_matched, ent->name, len))
214 continue;
216 LPCSTR sFileName;
218 if (!l_bFullPath)
220 sFileName = ent->name + prefix_offset;
222 else
224 strcpy(l_lpszFileName, ent->name);
225 sFileName = l_sFullPathBuf;
228 if (bIgnored)
230 // because we specified collect_all_ignored this may be a directory that was ignored
231 if (ent->name[ent->len-1] != '/')
233 if (l_bDirStatus)
235 l_nLastStatus = WGFS_Ignored;
236 update_dirs_unversioned(ent, len);
239 fputs("F I 0000000000000000000000000000000000000000 ", stdout);
241 else
243 if (l_bDirStatus)
245 const int nOrgEmptyDirStatus = l_nEmptyDirStatus;
246 l_nLastStatus = l_nEmptyDirStatus = WGFS_Ignored;
247 update_dirs_unversioned(ent, len);
248 l_nEmptyDirStatus = nOrgEmptyDirStatus;
251 continue;
254 else
256 if (ent->name[ent->len-1] != '/')
258 if (l_bDirStatus)
260 l_nLastStatus = WGFS_Unversioned;
261 update_dirs_unversioned(ent, len);
264 fputs("F U 0000000000000000000000000000000000000000 ", stdout);
266 else
268 if (l_bDirStatus)
270 l_nLastStatus = l_nEmptyDirStatus;
271 update_dirs_unversioned(ent, len);
274 continue;
277 fputs(sFileName, stdout);
278 fputc(0, stdout);
283 static inline BOOL enum_dir(struct DirStatus *dir, LPCSTR lpszPathName)
285 if (dir->nStatus == WGFS_Normal && l_bSkipNormalDirs)
286 return FALSE;
288 // output format: "D status pathname"
290 fputs("D ", stdout);
291 fputc(GetStatusChar(dir->nStatus), stdout);
292 fputc(' ', stdout);
293 fputs(lpszPathName, stdout);
294 fputc(0, stdout);
296 return FALSE;
299 static BOOL enum_dirs(struct DirStatus *dir, LPSTR sPathNameBuf)
301 const int len = strlen(dir->lpszName);
302 memcpy(sPathNameBuf, dir->lpszName, len);
303 sPathNameBuf += len;
304 *sPathNameBuf = 0;
306 if ( enum_dir(dir, l_bFullPath ? l_sFullPathBuf : l_sFullPathBuf+prefix_offset) )
307 return TRUE;
309 if (!l_bNoRecurse && dir->children)
311 // recurse
313 *sPathNameBuf++ = '/';
314 *sPathNameBuf = 0;
316 dir = dir->children;
318 while (dir)
320 if ( enum_dirs(dir, sPathNameBuf) )
321 return TRUE;
323 dir = dir->next;
327 return FALSE;
331 static struct DirStatus* GetSubDir(struct DirStatus *dir, LPCSTR lpszName, int nNameLenInclTerminator)
333 // check for cached access
334 if (dir->pLastAccessedChild
335 && !strcmp(dir->pLastAccessedChild->lpszName, lpszName))
337 return dir->pLastAccessedChild;
340 // search children
341 struct DirStatus *p = dir->children;
342 struct DirStatus *last = NULL;
343 while (p)
345 if ( !strcmp(p->lpszName, lpszName) )
346 return (dir->pLastAccessedChild = p);
348 last = p;
349 p = p->next;
352 // dir not accessed before, create new entry
353 // TODO: do more efficient allocator (allocate larger pools, they can still be fire and forget and let our garbage collector clean up)
354 p = dir->pLastAccessedChild = (struct DirStatus*) malloc(sizeof(struct DirStatus) + ((nNameLenInclTerminator+3)&~3));
356 p->pLastAccessedChild = NULL;
357 p->lpszName = (char*)p + sizeof(struct DirStatus);
358 p->next = NULL;
359 p->children = NULL;
360 p->parent = dir;
361 if (l_nEmptyDirStatus != WGFS_Ignored)
363 p->bExplicitlyIgnored = dir->bExplicitlyIgnored;
364 p->nStatus = (p->bExplicitlyIgnored && l_nEmptyDirStatus < WGFS_Ignored) ? WGFS_Ignored : l_nEmptyDirStatus;
366 else
368 p->nStatus = WGFS_Ignored;
369 p->bExplicitlyIgnored = TRUE;
372 // append to list
373 if (dir->children)
374 last->next = p;
375 else
376 dir->children = p;
378 // copy string
379 memcpy((char*)p->lpszName, lpszName, nNameLenInclTerminator);
381 return p;
385 static inline BOOL IsStatusRelevantForDirs(int nStatus)
387 return nStatus >= l_nMinStatusRelevantForDirs && nStatus != WGFS_Deleted;
391 static void update_dirs_unversioned_rec(LPCSTR lpszFileName, UINT nDirLen, struct dir_entry *ce, struct DirStatus *parentDir)
393 const int nDirLen1 = nDirLen+1;
394 char s[nDirLen1];
395 memcpy(s, lpszFileName, nDirLen);
396 s[nDirLen] = 0;
398 struct DirStatus *dir = GetSubDir(parentDir, s, nDirLen1);
399 //ASSERT(dir != NULL);
401 if (dir->nStatus >= WGFS_Conflicted && l_bNoRecurse)
403 // no further processing needed
404 return;
407 // process next subdir in lpszFileName
409 lpszFileName += nDirLen1;
411 LPCSTR p = strchr(lpszFileName, '/');
412 if (!p)
414 // no more dirs in pathname (ie we are in the dir the file is located)
416 if (l_nEmptyDirStatus == WGFS_Unknown)
417 // only want dirs enumerated without recursive status
418 return;
420 const int nFileStatus = l_nLastStatus;
422 if (nFileStatus > dir->nStatus)
424 // update status on dir and all parents
427 if (nFileStatus > dir->nStatus)
428 dir->nStatus = nFileStatus;
430 while ( (dir = dir->parent) );
433 else if (lpszFileName != p) // quick check to make sure we're not left with a "/" filename
435 update_dirs_unversioned_rec(lpszFileName, (UINT)(p-lpszFileName), ce, dir);
439 static void update_dirs_unversioned(struct dir_entry *ce, int nPathNameOffset)
441 // filename relative to enumerated path
442 LPCSTR lpszFileName = ce->name + nPathNameOffset;
444 LPCSTR p = strchr(lpszFileName, '/');
445 if (p <= lpszFileName)
447 // file is not in sub-dir
449 if (l_nEmptyDirStatus == WGFS_Unknown)
450 // only want dirst enumerated without recursive status
451 return;
453 const int nFileStatus = l_nLastStatus;
455 if (nFileStatus > l_dirTree.nStatus)
456 l_dirTree.nStatus = nFileStatus;
458 return;
461 if (!l_bNoRecurseDir)
463 update_dirs_unversioned_rec(lpszFileName, (UINT)(p-lpszFileName), ce, &l_dirTree);
468 static void update_dirs_rec(LPCSTR lpszFileName, UINT nDirLen, struct cache_entry *ce, BOOL bStatusCached, struct DirStatus *parentDir)
470 const int nDirLen1 = nDirLen+1;
471 char s[nDirLen1];
472 memcpy(s, lpszFileName, nDirLen);
473 s[nDirLen] = 0;
475 struct DirStatus *dir = GetSubDir(parentDir, s, nDirLen1);
476 //ASSERT(dir != NULL);
478 if (dir->nStatus >= WGFS_Conflicted && l_bNoRecurse)
480 // no further processing needed
481 return;
484 // process next subdir in lpszFileName
486 lpszFileName += nDirLen1;
488 LPCSTR p = strchr(lpszFileName, '/');
489 if (!p)
491 // no more dirs in pathname (ie we are in the dir the file is located)
493 if (l_nEmptyDirStatus == WGFS_Unknown)
494 // only want dirst enumerated without recursive status
495 return;
497 if (!bStatusCached)
499 // file status not determined yet, do it now
500 struct stat st;
501 int err = lstat(ce->name, &st);
502 if (!process_ce_entry_status(ce, err ? NULL : &st) || !IsStatusRelevantForDirs(l_nLastStatus))
503 return;
505 const int nFileStatus = l_nLastStatus;
507 if (nFileStatus > dir->nStatus)
509 // update status on dir and all parents
512 if (nFileStatus > dir->nStatus)
513 dir->nStatus = nFileStatus;
515 while ( (dir = dir->parent) );
518 else if (lpszFileName != p) // quick check to make sure we're not left with a "/" filename
520 update_dirs_rec(lpszFileName, (UINT)(p-lpszFileName), ce, bStatusCached, dir);
524 static void update_dirs(struct cache_entry *ce, int nPathNameOffset, BOOL bStatusCached)
526 // filename relative to enumerated path
527 LPCSTR lpszFileName = ce->name + nPathNameOffset;
529 LPCSTR p = strchr(lpszFileName, '/');
530 if (p <= lpszFileName)
532 // file is not in sub-dir
534 if (l_nEmptyDirStatus == WGFS_Unknown)
535 // only want dirs enumerated without recursive status
536 return;
538 if (!bStatusCached)
540 // file status not determined yet, do it now
541 struct stat st;
542 int err = lstat(ce->name, &st);
543 if (!process_ce_entry_status(ce, err ? NULL : &st) || !IsStatusRelevantForDirs(l_nLastStatus))
544 return;
546 const int nFileStatus = l_nLastStatus;
548 if (nFileStatus > l_dirTree.nStatus)
549 l_dirTree.nStatus = nFileStatus;
551 return;
554 if (!l_bNoRecurseDir)
556 update_dirs_rec(lpszFileName, (UINT)(p-lpszFileName), ce, bStatusCached, &l_dirTree);
561 static inline BOOL is_subpath(const char *sPath, int nPathLen, const char *sFile)
563 return strchr(sFile + nPathLen, '/') != NULL;
566 static BOOL is_dir(const char *sProjectPath, const char *sSubPath)
568 char s[2048];
570 strcpy(s, sProjectPath);
571 // backslashify
572 LPSTR q = s;
573 while (*q)
575 if (*q == '/')
576 *q = '\\';
577 q++;
579 // make sure it ends with a slash
580 if (q[-1] != '\\')
581 *q++ = '\\';
582 strcpy(q, sSubPath);
583 // backslashify sub-path
584 while (*q)
586 if (*q == '/')
587 *q = '\\';
588 q++;
591 struct stat st;
592 int err = lstat(s, &st);
594 return (!err && S_ISDIR(st.st_mode));
597 static inline BOOL is_ce_name_eq(struct cache_entry *ce1, struct cache_entry *ce2)
599 const size_t len1 = ce1->ce_flags & CE_NAMEMASK;
600 const size_t len2 = ce2->ce_flags & CE_NAMEMASK;
602 return (len1 == len2) ? !strcmp(ce1->name, ce2->name) : FALSE;
606 struct oneway_unpack_data {
607 struct rev_info *revs;
608 char symcache[PATH_MAX];
611 // modified version of function in diff-lib.c
612 static void do_oneway_diff(struct unpack_trees_options *o, struct cache_entry *idx, struct cache_entry *tree)
614 if (!tree)
616 if (idx)
618 // file has no previous commit, newly added
619 idx->ce_flags |= CE_IG_ADDED;
622 else if (!idx)
624 // file only in previous commit, deleted
625 tree->ce_flags |= CE_IG_DELETED;
626 queue_deleted(tree);
628 else if (!(idx->ce_flags & CE_INTENT_TO_ADD)
629 && hashcmp(tree->sha1, idx->sha1) && !is_null_sha1(idx->sha1))
631 // file modified and in both indices, staged
632 idx->ce_flags |= CE_IG_STAGED;
636 // function taken from diff-lib.c
637 static inline void skip_same_name(struct cache_entry *ce, struct unpack_trees_options *o)
639 int len = ce_namelen(ce);
640 const struct index_state *index = o->src_index;
642 while (o->pos < index->cache_nr) {
643 struct cache_entry *next = index->cache[o->pos];
644 if (len != ce_namelen(next))
645 break;
646 if (memcmp(ce->name, next->name, len))
647 break;
648 o->pos++;
652 // function taken from diff-lib.c
653 static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
655 struct cache_entry *idx = src[0];
656 struct cache_entry *tree = src[1];
657 struct oneway_unpack_data *cbdata = o->unpack_data;
658 struct rev_info *revs = cbdata->revs;
660 if (idx && ce_stage(idx))
661 skip_same_name(idx, o);
664 * Unpack-trees generates a DF/conflict entry if
665 * there was a directory in the index and a tree
666 * in the tree. From a diff standpoint, that's a
667 * delete of the tree and a create of the file.
669 if (tree == o->df_conflict_entry)
670 tree = NULL;
672 if (ce_path_match(idx ? idx : tree, revs->prune_data))
673 do_oneway_diff(o, idx, tree);
675 return 0;
679 * This turns all merge entries into "stage 3". That guarantees that
680 * when we read in the new tree (into "stage 1"), we won't lose sight
681 * of the fact that we had unmerged entries.
683 static void mark_merge_entries(void)
685 int i;
686 for (i = 0; i < active_nr; i++) {
687 struct cache_entry *ce = active_cache[i];
688 if (!ce_stage(ce))
689 continue;
690 ce->ce_flags |= CE_STAGEMASK;
694 static void preprocess_index(struct rev_info *revs)
696 // compare current index with index from last commit to detect staged and newly added files
699 // based on run_diff_index()
702 struct object *ent;
703 struct tree *tree;
704 const char *tree_name;
705 struct unpack_trees_options opts;
706 struct tree_desc t;
707 struct oneway_unpack_data unpack_cb;
709 mark_merge_entries();
711 ent = revs->pending.objects[0].item;
712 tree_name = revs->pending.objects[0].name;
713 tree = parse_tree_indirect(ent->sha1);
714 if (!tree)
715 // bad tree object
716 return;
718 unpack_cb.revs = revs;
719 unpack_cb.symcache[0] = '\0';
720 memset(&opts, 0, sizeof(opts));
721 opts.head_idx = 1;
722 opts.index_only = 1;
723 opts.merge = 1;
724 opts.fn = oneway_diff;
725 opts.unpack_data = &unpack_cb;
726 opts.src_index = &the_index;
727 opts.dst_index = NULL;
729 init_tree_desc(&t, tree->buffer, tree->size);
731 if ( unpack_trees(1, &t, &opts) )
732 // failed to unpack
733 return;
735 // add deleted files to index (easier for enumeration functions to process)
736 if (l_delQueue)
738 struct EntryRef *p = l_delQueue;
740 while (p)
742 // only add file for enumeration if they still exist
743 struct stat st;
744 if ( lstat(p->ce->name, &st) )
746 struct cache_entry *ce = make_cache_entry(p->ce->ce_mode, null_sha1, p->ce->name, 0, 0);
748 add_index_entry(&the_index, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK|ADD_CACHE_NEW_ONLY);
749 ce->ce_flags &= ~CE_ADDED;
750 ce->ce_flags |= CE_IG_DELETED;
753 struct EntryRef *q = p;
754 p = p->next;
756 free(q);
759 l_delQueue = NULL;
764 static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
766 struct object *object;
768 object = parse_object(sha1);
769 if (!object)
770 return NULL;//die("bad object %s", name);
771 object->flags |= flags;
772 return object;
775 static int add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode)
777 if (revs->no_walk && (obj->flags & UNINTERESTING))
778 return 1;//die("object ranges do not make sense when not walking revisions");
779 if (revs->reflog_info && obj->type == OBJ_COMMIT
780 && add_reflog_for_walk(revs->reflog_info, (struct commit *)obj, name))
781 return 0;
782 add_object_array_with_mode(obj, name, &revs->pending, mode);
783 return 0;
786 static int setup_revisions_lite(struct rev_info *revs, const char *def)
788 if (revs->def == NULL)
789 revs->def = def;
790 if (revs->def && !revs->pending.nr) {
791 unsigned char sha1[20];
792 struct object *object;
793 unsigned mode;
794 if (get_sha1_with_mode(revs->def, sha1, &mode))
795 return 1;//die("bad default revision '%s'", revs->def);
796 object = get_reference(revs, revs->def, sha1, 0);
797 if (!object)
798 return 2;
799 if ( add_pending_object_with_mode(revs, object, revs->def, mode) )
800 return 3;
803 /* Did the user ask for any diff output? Run the diff! */
804 if (revs->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT)
805 revs->diff = 1;
807 /* Pickaxe, diff-filter and rename following need diffs */
808 if (revs->diffopt.pickaxe ||
809 revs->diffopt.filter ||
810 DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
811 revs->diff = 1;
813 if (revs->topo_order)
814 revs->limited = 1;
816 if (revs->prune_data) {
817 diff_tree_setup_paths(revs->prune_data, &revs->pruning);
818 /* Can't prune commits with rename following: the paths change.. */
819 if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
820 revs->prune = 1;
821 if (!revs->full_diff)
822 diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
824 if (revs->combine_merges) {
825 revs->ignore_merges = 0;
826 if (revs->dense_combined_merges && !revs->diffopt.output_format)
827 revs->diffopt.output_format = DIFF_FORMAT_PATCH;
829 revs->diffopt.abbrev = revs->abbrev;
830 if (diff_setup_done(&revs->diffopt) < 0)
831 return 4;//die("diff_setup_done failed");
833 compile_grep_patterns(&revs->grep_filter);
835 /*if (revs->reverse && revs->reflog_info)
836 die("cannot combine --reverse with --walk-reflogs");
837 if (revs->rewrite_parents && revs->children.name)
838 die("cannot combine --parents and --children");*/
841 * Limitations on the graph functionality
843 /*if (revs->reverse && revs->graph)
844 die("cannot combine --reverse with --graph");
846 if (revs->reflog_info && revs->graph)
847 die("cannot combine --walk-reflogs with --graph");*/
849 return 0;
854 BOOL ig_enum_files(const char *pszProjectPath, const char *pszSubPath, const char *prefix, unsigned int nFlags)
856 // reset all local vars of builtin-ls-files.c to default
857 abbrev = 0;
858 show_deleted = 0;
859 show_cached = 0;
860 show_others = 0;
861 show_stage = 0;
862 show_unmerged = 0;
863 show_modified = 0;
864 show_killed = 0;
865 show_valid_bit = 0;
866 line_terminator = '\n';
867 prefix_len = 0;
868 prefix_offset = 0;
869 pathspec = 0;
870 error_unmatch = 0;
871 ps_matched = 0;
872 with_tree = 0;
873 tag_cached = "";
874 tag_unmerged = "";
875 tag_removed = "";
876 tag_other = "";
877 tag_killed = "";
878 tag_modified = "";
880 const BOOL bSubDir = pszSubPath && is_dir(pszProjectPath, pszSubPath);
882 LPCSTR pszSubPathSpec = pszSubPath;
883 if (bSubDir && !(nFlags & WGEFF_SingleFile))
885 int len = strlen(pszSubPath);
886 char *s = (char*)malloc(len+3);
887 strcpy(s, pszSubPath);
888 strcpy(s+len, "/*");
889 pszSubPathSpec = s;
892 int i;
893 //int exc_given = 0, require_work_tree = 0;
894 struct dir_struct _dir;
896 memset(&_dir, 0, sizeof(_dir));
898 memset(&l_dirTree, 0, sizeof(l_dirTree));
899 l_dirTree.nStatus = WGFS_Normal; // root dir is always at least WGFS_Normal even if empty
900 if (pszSubPath && !(nFlags & WGEFF_EmptyAsNormal))
901 l_dirTree.nStatus = WGFS_Empty;
903 // NOTE: to force names to be relative to project root dir (no mater what current dir is) set prefix_offset to 0
904 if (prefix)
905 prefix_offset = strlen(prefix);
906 git_config(git_default_config, NULL);
908 struct dir_struct *dir = &_dir;
910 const char *argv[2];
911 argv[0] = pszSubPathSpec;
912 argv[1] = NULL;
914 if (/*require_work_tree &&*/ !is_inside_work_tree())
915 setup_work_tree();
917 pathspec = get_pathspec(prefix, argv);
919 // Verify that the pathspec matches the prefix
920 if (pathspec)
921 prefix = verify_pathspec(prefix);
923 // Treat unmatching pathspec elements as errors
924 if (pathspec && error_unmatch)
926 int num;
927 for (num = 0; pathspec[num]; num++)
929 ps_matched = xcalloc(1, num);
932 // vars used for path recursion check
933 int pathspec_len = 0;
934 if (pathspec && *pathspec)
936 // calc length of pathspec plus 1 for a / (unless it already ends with a slash)
937 pathspec_len = strlen(*pathspec);
938 if ((*pathspec)[pathspec_len-1] == '*')
939 pathspec_len--;
940 if ((*pathspec)[pathspec_len-1] != '/')
941 pathspec_len++;
943 const char *refpath = (pathspec && *pathspec) ? *pathspec : "";
946 // configure
949 l_bNoRecurseDir = FALSE;
951 BOOL single_dir = (nFlags & WGEFF_SingleFile) && (!pszSubPath || bSubDir);
952 // adjust other flags for best performance / correct results when WGEFF_SingleFile is set
953 if (single_dir && (nFlags & WGEFF_NoRecurse))
954 l_bNoRecurseDir = TRUE;
955 if (nFlags & WGEFF_SingleFile)
957 nFlags |= WGEFF_NoRecurse;
958 if (!single_dir)
959 nFlags &= ~(WGEFF_DirStatusAll|WGEFF_DirStatusDelta);
961 if (single_dir)
963 nFlags = (nFlags & ~WGEFF_DirStatusAll) | WGEFF_DirStatusDelta;
965 if ( !(nFlags & WGEFF_EmptyAsNormal) )
966 l_dirTree.nStatus = WGFS_Empty;
969 BOOL no_recurse = nFlags & WGEFF_NoRecurse;
970 l_bNoRecurse = no_recurse;
971 l_bFullPath = nFlags & WGEFF_FullPath;
972 l_bDirStatus = nFlags & (WGEFF_DirStatusDelta|WGEFF_DirStatusAll);
974 // when all dirs should be enumerated we need IsStatusRelevantForDirs to report files of any status as relevant
975 // otherwise only above normal are considered, which is slightly more efficient
976 l_nMinStatusRelevantForDirs = (nFlags & WGEFF_DirStatusAll) ? WGFS_Empty : (WGFS_Normal+1);
978 // initial status of dirs
979 l_nEmptyDirStatus = (nFlags & WGEFF_EmptyAsNormal) ? WGFS_Normal : WGFS_Empty;
981 l_bSkipNormalDirs = ((nFlags & (WGEFF_DirStatusDelta|WGEFF_DirStatusAll)) == WGEFF_DirStatusDelta);
983 if (!(nFlags & WGEFF_SingleFile) && !l_bDirStatus)
985 // no recursive dir status requested, list all dirs as unknown
986 l_bDirStatus = TRUE;
987 l_nEmptyDirStatus = l_nMinStatusRelevantForDirs = WGFS_Unknown;
988 l_bSkipNormalDirs = FALSE;
989 l_dirTree.nStatus = WGFS_Unknown;
992 *l_sFullPathBuf = 0;
993 l_lpszFileName = NULL;
994 if (l_bFullPath)
996 strcpy(l_sFullPathBuf, pszProjectPath);
997 // slashify
998 LPSTR q = l_sFullPathBuf;
999 while (*q)
1001 if (*q == '\\')
1002 *q = '/';
1003 q++;
1005 // make sure it ends with a slash
1006 if (q[-1] != '/')
1008 *q++ = '/';
1009 *q = 0;
1011 // save pointer to where file paths, with project-relative names, can be concatenated
1012 l_lpszFileName = q;
1015 // shouldn't have any effect but set them to reflect what we want listed
1016 show_cached = 1;
1017 show_modified = 1;
1018 show_deleted = 1;
1019 show_unmerged = 1;
1021 struct rev_info rev;
1022 init_revisions(&rev, prefix);
1023 rev.ignore_merges = 0;
1024 rev.no_walk = 1;
1025 rev.max_count = 1;
1026 l_bHasHistory = !setup_revisions_lite(&rev, "HEAD");
1028 read_cache();
1029 if (l_bHasHistory)
1030 preprocess_index(&rev);
1031 if (prefix)
1032 prune_cache(prefix);
1034 //if (pathspec && *pathspec) OutputDebugString(*pathspec);OutputDebugString(" (1)\r\n");
1035 //if (prefix) OutputDebugString(prefix);OutputDebugString(" (2)\r\n");
1038 // enum files
1041 for (i=0; i<active_nr; i++)
1043 struct cache_entry *ce = active_cache[i];
1044 struct stat st;
1045 int err;
1047 int dtype = ce_to_dtype(ce);
1049 if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
1050 continue;
1051 if (ce->ce_flags & CE_UPDATE)
1052 continue;
1054 // skip file if not inside specified sub-path
1055 // this test was originally done in enum_ce_entry but in order to avoid unecessery lstat calls it was moved
1056 if (prefix_len >= ce_namelen(ce))
1057 die("git ls-files: internal error - cache entry not superset of prefix");
1058 if (pathspec && !pathspec_match(pathspec, ps_matched, ce->name, prefix_len))
1059 continue;
1061 if (single_dir || (no_recurse && is_subpath(refpath, pathspec_len, ce->name)))
1063 if (l_bDirStatus)
1064 // this file would normally be skipped, but in order to determine correct dir status we need to process it
1065 update_dirs(ce, pathspec_len, FALSE);
1067 continue;
1070 err = (ce->ce_flags & CE_IG_DELETED) ? 1 : lstat(ce->name, &st);
1072 if ( enum_ce_entry(ce, err ? NULL : &st) )
1073 return TRUE;
1075 // normally (always?) conflicted/unmerged files will have 3 entries in a row (one in stage 1, one in 2 and one in 3)
1076 // skip redundant entries here
1077 if ( ce_stage(ce) )
1079 int j;
1081 for (j=i+1; j<active_nr; j++)
1083 struct cache_entry *nextce = active_cache[j];
1085 if ( !is_ce_name_eq(ce, nextce) )
1086 break;
1088 i = j;
1092 if (l_bDirStatus && IsStatusRelevantForDirs(l_nLastStatus))
1093 update_dirs(ce, pathspec_len, TRUE);
1096 BOOL bIgnoreInitialized = FALSE;
1098 if (pszSubPath)
1100 // check if root (pszSubPath) dir is ignored
1102 if (!bIgnoreInitialized)
1104 setup_standard_excludes(dir);
1105 bIgnoreInitialized = TRUE;
1108 char sDir[MAX_PATH];
1109 strcpy(sDir, pszSubPath);
1110 LPSTR p = strrchr(sDir, '/');
1111 if (p) *p = 0;
1113 int dtype = DT_DIR;
1114 // check for matching ignore for each subdir level
1115 p = strchr(sDir, '/');
1116 for (;;)
1118 if (p)
1119 *p = 0;
1121 if ( excluded(dir, sDir, &dtype) )
1123 l_dirTree.nStatus = WGFS_Ignored;
1124 l_dirTree.bExplicitlyIgnored = TRUE;
1127 if (p)
1129 *p = '/';
1130 p = strchr(p+1, '/');
1131 if (!p)
1132 break;
1134 else
1136 break;
1141 // enumerate unversioned files
1142 if ( !(nFlags & WGEFF_SingleFile) )
1144 const char *path = ".", *base = "";
1145 int baselen = prefix_len;
1147 if (baselen)
1148 path = base = prefix;
1150 if (!bIgnoreInitialized)
1152 setup_standard_excludes(dir);
1153 bIgnoreInitialized = TRUE;
1155 dir->collect_ignored = 1;
1156 dir->show_ignored = 0;
1157 dir->show_other_directories = 0;
1158 dir->hide_empty_directories = 0;
1159 dir->collect_all_ignored = 1;
1160 dir->collect_directories = 1;
1161 dir->no_recurse_readdir = no_recurse ? 1 : 0;
1162 read_directory(dir, path, base, baselen, pathspec);
1164 // if root dir is ignored, then all unversioned files under it are considered ignore
1165 enum_unversioned(dir->entries, dir->nr, l_dirTree.bExplicitlyIgnored);
1166 enum_unversioned(dir->ignored, dir->ignored_nr, TRUE);
1168 else if (!single_dir && !l_nEnumeratedCached)
1170 // get status of a single unversioned file
1172 if (!bIgnoreInitialized)
1174 setup_standard_excludes(dir);
1175 bIgnoreInitialized = TRUE;
1178 LPCSTR sFileName;
1180 if (!l_bFullPath)
1182 sFileName = pszSubPath + prefix_offset;
1184 else
1186 strcpy(l_lpszFileName, pszSubPath);
1187 sFileName = l_sFullPathBuf;
1190 int dtype = DT_REG;
1191 // if root dir is ignored, then all unversioned files under it are considered ignore
1192 if (!l_dirTree.bExplicitlyIgnored && excluded(dir, pszSubPath, &dtype))
1193 fputs("F I 0000000000000000000000000000000000000000 ", stdout);
1194 else
1195 fputs("F U 0000000000000000000000000000000000000000 ", stdout);
1196 fputs(sFileName, stdout);
1197 fputc(0, stdout);
1200 if (l_bDirStatus)
1202 // enumerate dirs
1204 LPCSTR lpszRootDir="/";
1205 if (l_bFullPath)
1207 lpszRootDir = l_sFullPathBuf;
1208 if (pathspec_len)
1210 strcpy(l_lpszFileName, *pathspec);
1211 l_lpszFileName += pathspec_len;
1214 *l_lpszFileName = 0;
1215 // remove trailng slash
1216 l_lpszFileName[-1] = 0;
1218 else if (pathspec_len)
1220 lpszRootDir = ".";
1222 strcpy(l_sFullPathBuf, *pathspec);
1223 l_sFullPathBuf[pathspec_len-1] = '/';
1224 l_sFullPathBuf[pathspec_len] = 0;
1225 l_lpszFileName = l_sFullPathBuf;
1227 else
1229 lpszRootDir = ".";
1231 l_lpszFileName = l_sFullPathBuf;
1234 if (single_dir)
1236 // enumerate single dir
1237 l_bSkipNormalDirs = FALSE;
1238 enum_dir(&l_dirTree, lpszRootDir);
1240 else if (!enum_dir(&l_dirTree, lpszRootDir) && l_dirTree.children)
1242 if (l_bFullPath)
1243 // re-add trailing slash
1244 l_lpszFileName[-1] = '/';
1246 struct DirStatus *p = l_dirTree.children;
1250 if ( enum_dirs(p, l_lpszFileName) )
1251 break;
1253 while ( (p = p->next) );
1257 return TRUE;
1261 #if 0
1264 * This merges the file listing in the directory cache index
1265 * with the actual working directory list, and shows different
1266 * combinations of the two.
1268 * Copyright (C) Linus Torvalds, 2005
1270 #include "cache.h"
1271 #include "quote.h"
1272 #include "dir.h"
1273 #include "builtin.h"
1274 #include "tree.h"
1276 static int abbrev;
1277 static int show_deleted;
1278 static int show_cached;
1279 static int show_others;
1280 static int show_stage;
1281 static int show_unmerged;
1282 static int show_modified;
1283 static int show_killed;
1284 static int show_valid_bit;
1285 static int line_terminator = '\n';
1287 static int prefix_len;
1288 static int prefix_offset;
1289 static const char **pathspec;
1290 static int error_unmatch;
1291 static char *ps_matched;
1292 static const char *with_tree;
1294 static const char *tag_cached = "";
1295 static const char *tag_unmerged = "";
1296 static const char *tag_removed = "";
1297 static const char *tag_other = "";
1298 static const char *tag_killed = "";
1299 static const char *tag_modified = "";
1303 * Match a pathspec against a filename. The first "skiplen" characters
1304 * are the common prefix
1306 int pathspec_match(const char **spec, char *ps_matched,
1307 const char *filename, int skiplen)
1309 const char *m;
1311 while ((m = *spec++) != NULL) {
1312 int matchlen = strlen(m + skiplen);
1314 if (!matchlen)
1315 goto matched;
1316 if (!strncmp(m + skiplen, filename + skiplen, matchlen)) {
1317 if (m[skiplen + matchlen - 1] == '/')
1318 goto matched;
1319 switch (filename[skiplen + matchlen]) {
1320 case '/': case '\0':
1321 goto matched;
1324 if (!fnmatch(m + skiplen, filename + skiplen, 0))
1325 goto matched;
1326 if (ps_matched)
1327 ps_matched++;
1328 continue;
1329 matched:
1330 if (ps_matched)
1331 *ps_matched = 1;
1332 return 1;
1334 return 0;
1337 static void show_dir_entry(const char *tag, struct dir_entry *ent)
1339 int len = prefix_len;
1340 int offset = prefix_offset;
1342 if (len >= ent->len)
1343 die("git ls-files: internal error - directory entry not superset of prefix");
1345 if (pathspec && !pathspec_match(pathspec, ps_matched, ent->name, len))
1346 return;
1348 fputs(tag, stdout);
1349 write_name_quoted(ent->name + offset, stdout, line_terminator);
1352 static void show_other_files(struct dir_struct *dir)
1354 int i;
1356 for (i = 0; i < dir->nr; i++) {
1357 struct dir_entry *ent = dir->entries[i];
1358 if (!cache_name_is_other(ent->name, ent->len))
1359 continue;
1360 show_dir_entry(tag_other, ent);
1364 static void show_killed_files(struct dir_struct *dir)
1366 int i;
1367 for (i = 0; i < dir->nr; i++) {
1368 struct dir_entry *ent = dir->entries[i];
1369 char *cp, *sp;
1370 int pos, len, killed = 0;
1372 for (cp = ent->name; cp - ent->name < ent->len; cp = sp + 1) {
1373 sp = strchr(cp, '/');
1374 if (!sp) {
1375 /* If ent->name is prefix of an entry in the
1376 * cache, it will be killed.
1378 pos = cache_name_pos(ent->name, ent->len);
1379 if (0 <= pos)
1380 die("bug in show-killed-files");
1381 pos = -pos - 1;
1382 while (pos < active_nr &&
1383 ce_stage(active_cache[pos]))
1384 pos++; /* skip unmerged */
1385 if (active_nr <= pos)
1386 break;
1387 /* pos points at a name immediately after
1388 * ent->name in the cache. Does it expect
1389 * ent->name to be a directory?
1391 len = ce_namelen(active_cache[pos]);
1392 if ((ent->len < len) &&
1393 !strncmp(active_cache[pos]->name,
1394 ent->name, ent->len) &&
1395 active_cache[pos]->name[ent->len] == '/')
1396 killed = 1;
1397 break;
1399 if (0 <= cache_name_pos(ent->name, sp - ent->name)) {
1400 /* If any of the leading directories in
1401 * ent->name is registered in the cache,
1402 * ent->name will be killed.
1404 killed = 1;
1405 break;
1408 if (killed)
1409 show_dir_entry(tag_killed, dir->entries[i]);
1413 static void show_ce_entry(const char *tag, struct cache_entry *ce)
1415 int len = prefix_len;
1416 int offset = prefix_offset;
1418 if (len >= ce_namelen(ce))
1419 die("git ls-files: internal error - cache entry not superset of prefix");
1421 if (pathspec && !pathspec_match(pathspec, ps_matched, ce->name, len))
1422 return;
1424 if (tag && *tag && show_valid_bit &&
1425 (ce->ce_flags & CE_VALID)) {
1426 static char alttag[4];
1427 memcpy(alttag, tag, 3);
1428 if (isalpha(tag[0]))
1429 alttag[0] = tolower(tag[0]);
1430 else if (tag[0] == '?')
1431 alttag[0] = '!';
1432 else {
1433 alttag[0] = 'v';
1434 alttag[1] = tag[0];
1435 alttag[2] = ' ';
1436 alttag[3] = 0;
1438 tag = alttag;
1441 if (!show_stage) {
1442 fputs(tag, stdout);
1443 } else {
1444 printf("%s%06o %s %d\t",
1445 tag,
1446 ce->ce_mode,
1447 abbrev ? find_unique_abbrev(ce->sha1,abbrev)
1448 : sha1_to_hex(ce->sha1),
1449 ce_stage(ce));
1451 write_name_quoted(ce->name + offset, stdout, line_terminator);
1454 static void show_files(struct dir_struct *dir, const char *prefix)
1456 int i;
1458 /* For cached/deleted files we don't need to even do the readdir */
1459 if (show_others || show_killed) {
1460 const char *path = ".", *base = "";
1461 int baselen = prefix_len;
1463 if (baselen)
1464 path = base = prefix;
1465 read_directory(dir, path, base, baselen, pathspec);
1466 if (show_others)
1467 show_other_files(dir);
1468 if (show_killed)
1469 show_killed_files(dir);
1471 if (show_cached | show_stage) {
1472 for (i = 0; i < active_nr; i++) {
1473 struct cache_entry *ce = active_cache[i];
1474 int dtype = ce_to_dtype(ce);
1475 if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
1476 continue;
1477 if (show_unmerged && !ce_stage(ce))
1478 continue;
1479 if (ce->ce_flags & CE_UPDATE)
1480 continue;
1481 show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);
1484 if (show_deleted | show_modified) {
1485 for (i = 0; i < active_nr; i++) {
1486 struct cache_entry *ce = active_cache[i];
1487 struct stat st;
1488 int err;
1489 int dtype = ce_to_dtype(ce);
1490 if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
1491 continue;
1492 if (ce->ce_flags & CE_UPDATE)
1493 continue;
1494 err = lstat(ce->name, &st);
1495 if (show_deleted && err)
1496 show_ce_entry(tag_removed, ce);
1497 if (show_modified && ce_modified(ce, &st, 0))
1498 show_ce_entry(tag_modified, ce);
1504 * Prune the index to only contain stuff starting with "prefix"
1506 static void prune_cache(const char *prefix)
1508 int pos = cache_name_pos(prefix, prefix_len);
1509 unsigned int first, last;
1511 if (pos < 0)
1512 pos = -pos-1;
1513 memmove(active_cache, active_cache + pos,
1514 (active_nr - pos) * sizeof(struct cache_entry *));
1515 active_nr -= pos;
1516 first = 0;
1517 last = active_nr;
1518 while (last > first) {
1519 int next = (last + first) >> 1;
1520 struct cache_entry *ce = active_cache[next];
1521 if (!strncmp(ce->name, prefix, prefix_len)) {
1522 first = next+1;
1523 continue;
1525 last = next;
1527 active_nr = last;
1530 static const char *verify_pathspec(const char *prefix)
1532 const char **p, *n, *prev;
1533 unsigned long max;
1535 prev = NULL;
1536 max = PATH_MAX;
1537 for (p = pathspec; (n = *p) != NULL; p++) {
1538 int i, len = 0;
1539 for (i = 0; i < max; i++) {
1540 char c = n[i];
1541 if (prev && prev[i] != c)
1542 break;
1543 if (!c || c == '*' || c == '?')
1544 break;
1545 if (c == '/')
1546 len = i+1;
1548 prev = n;
1549 if (len < max) {
1550 max = len;
1551 if (!max)
1552 break;
1556 if (prefix_offset > max || memcmp(prev, prefix, prefix_offset))
1557 die("git ls-files: cannot generate relative filenames containing '..'");
1559 prefix_len = max;
1560 return max ? xmemdupz(prev, max) : NULL;
1564 * Read the tree specified with --with-tree option
1565 * (typically, HEAD) into stage #1 and then
1566 * squash them down to stage #0. This is used for
1567 * --error-unmatch to list and check the path patterns
1568 * that were given from the command line. We are not
1569 * going to write this index out.
1571 void overlay_tree_on_cache(const char *tree_name, const char *prefix)
1573 struct tree *tree;
1574 unsigned char sha1[20];
1575 const char **match;
1576 struct cache_entry *last_stage0 = NULL;
1577 int i;
1579 if (get_sha1(tree_name, sha1))
1580 die("tree-ish %s not found.", tree_name);
1581 tree = parse_tree_indirect(sha1);
1582 if (!tree)
1583 die("bad tree-ish %s", tree_name);
1585 /* Hoist the unmerged entries up to stage #3 to make room */
1586 for (i = 0; i < active_nr; i++) {
1587 struct cache_entry *ce = active_cache[i];
1588 if (!ce_stage(ce))
1589 continue;
1590 ce->ce_flags |= CE_STAGEMASK;
1593 if (prefix) {
1594 static const char *(matchbuf[2]);
1595 matchbuf[0] = prefix;
1596 matchbuf[1] = NULL;
1597 match = matchbuf;
1598 } else
1599 match = NULL;
1600 if (read_tree(tree, 1, match))
1601 die("unable to read tree entries %s", tree_name);
1603 for (i = 0; i < active_nr; i++) {
1604 struct cache_entry *ce = active_cache[i];
1605 switch (ce_stage(ce)) {
1606 case 0:
1607 last_stage0 = ce;
1608 /* fallthru */
1609 default:
1610 continue;
1611 case 1:
1613 * If there is stage #0 entry for this, we do not
1614 * need to show it. We use CE_UPDATE bit to mark
1615 * such an entry.
1617 if (last_stage0 &&
1618 !strcmp(last_stage0->name, ce->name))
1619 ce->ce_flags |= CE_UPDATE;
1624 int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset)
1627 * Make sure all pathspec matched; otherwise it is an error.
1629 int num, errors = 0;
1630 for (num = 0; pathspec[num]; num++) {
1631 int other, found_dup;
1633 if (ps_matched[num])
1634 continue;
1636 * The caller might have fed identical pathspec
1637 * twice. Do not barf on such a mistake.
1639 for (found_dup = other = 0;
1640 !found_dup && pathspec[other];
1641 other++) {
1642 if (other == num || !ps_matched[other])
1643 continue;
1644 if (!strcmp(pathspec[other], pathspec[num]))
1646 * Ok, we have a match already.
1648 found_dup = 1;
1650 if (found_dup)
1651 continue;
1653 error("pathspec '%s' did not match any file(s) known to git.",
1654 pathspec[num] + prefix_offset);
1655 errors++;
1657 return errors;
1660 static const char ls_files_usage[] =
1661 "git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
1662 "[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
1663 "[ --exclude-per-directory=<filename> ] [--exclude-standard] "
1664 "[--full-name] [--abbrev] [--] [<file>]*";
1666 int cmd_ls_files(int argc, const char **argv, const char *prefix)
1668 int i;
1669 int exc_given = 0, require_work_tree = 0;
1670 struct dir_struct dir;
1672 memset(&dir, 0, sizeof(dir));
1673 if (prefix)
1674 prefix_offset = strlen(prefix);
1675 git_config(git_default_config, NULL);
1677 for (i = 1; i < argc; i++) {
1678 const char *arg = argv[i];
1680 if (!strcmp(arg, "--")) {
1681 i++;
1682 break;
1684 if (!strcmp(arg, "-z")) {
1685 line_terminator = 0;
1686 continue;
1688 if (!strcmp(arg, "-t") || !strcmp(arg, "-v")) {
1689 tag_cached = "H ";
1690 tag_unmerged = "M ";
1691 tag_removed = "R ";
1692 tag_modified = "C ";
1693 tag_other = "? ";
1694 tag_killed = "K ";
1695 if (arg[1] == 'v')
1696 show_valid_bit = 1;
1697 continue;
1699 if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) {
1700 show_cached = 1;
1701 continue;
1703 if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
1704 show_deleted = 1;
1705 continue;
1707 if (!strcmp(arg, "-m") || !strcmp(arg, "--modified")) {
1708 show_modified = 1;
1709 require_work_tree = 1;
1710 continue;
1712 if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) {
1713 show_others = 1;
1714 require_work_tree = 1;
1715 continue;
1717 if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) {
1718 dir.show_ignored = 1;
1719 require_work_tree = 1;
1720 continue;
1722 if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) {
1723 show_stage = 1;
1724 continue;
1726 if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
1727 show_killed = 1;
1728 require_work_tree = 1;
1729 continue;
1731 if (!strcmp(arg, "--directory")) {
1732 dir.show_other_directories = 1;
1733 continue;
1735 if (!strcmp(arg, "--no-empty-directory")) {
1736 dir.hide_empty_directories = 1;
1737 continue;
1739 if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
1740 /* There's no point in showing unmerged unless
1741 * you also show the stage information.
1743 show_stage = 1;
1744 show_unmerged = 1;
1745 continue;
1747 if (!strcmp(arg, "-x") && i+1 < argc) {
1748 exc_given = 1;
1749 add_exclude(argv[++i], "", 0, &dir.exclude_list[EXC_CMDL]);
1750 continue;
1752 if (!prefixcmp(arg, "--exclude=")) {
1753 exc_given = 1;
1754 add_exclude(arg+10, "", 0, &dir.exclude_list[EXC_CMDL]);
1755 continue;
1757 if (!strcmp(arg, "-X") && i+1 < argc) {
1758 exc_given = 1;
1759 add_excludes_from_file(&dir, argv[++i]);
1760 continue;
1762 if (!prefixcmp(arg, "--exclude-from=")) {
1763 exc_given = 1;
1764 add_excludes_from_file(&dir, arg+15);
1765 continue;
1767 if (!prefixcmp(arg, "--exclude-per-directory=")) {
1768 exc_given = 1;
1769 dir.exclude_per_dir = arg + 24;
1770 continue;
1772 if (!strcmp(arg, "--exclude-standard")) {
1773 exc_given = 1;
1774 setup_standard_excludes(&dir);
1775 continue;
1777 if (!strcmp(arg, "--full-name")) {
1778 prefix_offset = 0;
1779 continue;
1781 if (!strcmp(arg, "--error-unmatch")) {
1782 error_unmatch = 1;
1783 continue;
1785 if (!prefixcmp(arg, "--with-tree=")) {
1786 with_tree = arg + 12;
1787 continue;
1789 if (!prefixcmp(arg, "--abbrev=")) {
1790 abbrev = strtoul(arg+9, NULL, 10);
1791 if (abbrev && abbrev < MINIMUM_ABBREV)
1792 abbrev = MINIMUM_ABBREV;
1793 else if (abbrev > 40)
1794 abbrev = 40;
1795 continue;
1797 if (!strcmp(arg, "--abbrev")) {
1798 abbrev = DEFAULT_ABBREV;
1799 continue;
1801 if (*arg == '-')
1802 usage(ls_files_usage);
1803 break;
1806 if (require_work_tree && !is_inside_work_tree())
1807 setup_work_tree();
1809 pathspec = get_pathspec(prefix, argv + i);
1811 /* Verify that the pathspec matches the prefix */
1812 if (pathspec)
1813 prefix = verify_pathspec(prefix);
1815 /* Treat unmatching pathspec elements as errors */
1816 if (pathspec && error_unmatch) {
1817 int num;
1818 for (num = 0; pathspec[num]; num++)
1820 ps_matched = xcalloc(1, num);
1823 if (dir.show_ignored && !exc_given) {
1824 fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
1825 argv[0]);
1826 exit(1);
1829 /* With no flags, we default to showing the cached files */
1830 if (!(show_stage | show_deleted | show_others | show_unmerged |
1831 show_killed | show_modified))
1832 show_cached = 1;
1834 read_cache();
1835 if (prefix)
1836 prune_cache(prefix);
1837 if (with_tree) {
1839 * Basic sanity check; show-stages and show-unmerged
1840 * would not make any sense with this option.
1842 if (show_stage || show_unmerged)
1843 die("ls-files --with-tree is incompatible with -s or -u");
1844 overlay_tree_on_cache(with_tree, prefix);
1846 show_files(&dir, prefix);
1848 if (ps_matched) {
1849 int bad;
1850 bad = report_path_error(ps_matched, pathspec, prefix_offset);
1851 if (bad)
1852 fprintf(stderr, "Did you forget to 'git add'?\n");
1854 return bad ? 1 : 0;
1857 return 0;
1860 #endif