@@ -991,18 +991,23 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
991991 }
992992}
993993
994- struct diffstat_dir {
995- struct diffstat_file * * files ;
996- int nr , percent , cumulative ;
994+ struct dirstat_file {
995+ const char * name ;
996+ unsigned long changed ;
997997};
998998
999- static long gather_dirstat (FILE * file , struct diffstat_dir * dir , unsigned long changed , const char * base , int baselen )
999+ struct dirstat_dir {
1000+ struct dirstat_file * files ;
1001+ int alloc , nr , percent , cumulative ;
1002+ };
1003+
1004+ static long gather_dirstat (FILE * file , struct dirstat_dir * dir , unsigned long changed , const char * base , int baselen )
10001005{
10011006 unsigned long this_dir = 0 ;
10021007 unsigned int sources = 0 ;
10031008
10041009 while (dir -> nr ) {
1005- struct diffstat_file * f = * dir -> files ;
1010+ struct dirstat_file * f = dir -> files ;
10061011 int namelen = strlen (f -> name );
10071012 unsigned long this ;
10081013 char * slash ;
@@ -1017,10 +1022,7 @@ static long gather_dirstat(FILE *file, struct diffstat_dir *dir, unsigned long c
10171022 this = gather_dirstat (file , dir , changed , f -> name , newbaselen );
10181023 sources ++ ;
10191024 } else {
1020- if (f -> is_unmerged || f -> is_binary )
1021- this = 0 ;
1022- else
1023- this = f -> added + f -> deleted ;
1025+ this = f -> changed ;
10241026 dir -> files ++ ;
10251027 dir -> nr -- ;
10261028 sources += 2 ;
@@ -1048,30 +1050,65 @@ static long gather_dirstat(FILE *file, struct diffstat_dir *dir, unsigned long c
10481050 return this_dir ;
10491051}
10501052
1051- static void show_dirstat (struct diffstat_t * data , struct diff_options * options )
1053+ static void show_dirstat (struct diff_options * options )
10521054{
10531055 int i ;
10541056 unsigned long changed ;
1055- struct diffstat_dir dir ;
1057+ struct dirstat_dir dir ;
1058+ struct diff_queue_struct * q = & diff_queued_diff ;
1059+
1060+ dir .files = NULL ;
1061+ dir .alloc = 0 ;
1062+ dir .nr = 0 ;
1063+ dir .percent = options -> dirstat_percent ;
1064+ dir .cumulative = options -> output_format & DIFF_FORMAT_CUMULATIVE ;
10561065
1057- /* Calculate total changes */
10581066 changed = 0 ;
1059- for (i = 0 ; i < data -> nr ; i ++ ) {
1060- if (data -> files [i ]-> is_binary || data -> files [i ]-> is_unmerged )
1067+ for (i = 0 ; i < q -> nr ; i ++ ) {
1068+ struct diff_filepair * p = q -> queue [i ];
1069+ const char * name ;
1070+ unsigned long copied , added , damage ;
1071+
1072+ name = p -> one -> path ? p -> one -> path : p -> two -> path ;
1073+
1074+ if (DIFF_FILE_VALID (p -> one ) && DIFF_FILE_VALID (p -> two )) {
1075+ diff_populate_filespec (p -> one , 0 );
1076+ diff_populate_filespec (p -> two , 0 );
1077+ diffcore_count_changes (p -> one , p -> two , NULL , NULL , 0 ,
1078+ & copied , & added );
1079+ diff_free_filespec_data (p -> one );
1080+ diff_free_filespec_data (p -> two );
1081+ } else if (DIFF_FILE_VALID (p -> one )) {
1082+ diff_populate_filespec (p -> one , 1 );
1083+ copied = added = 0 ;
1084+ diff_free_filespec_data (p -> one );
1085+ } else if (DIFF_FILE_VALID (p -> two )) {
1086+ diff_populate_filespec (p -> two , 1 );
1087+ copied = 0 ;
1088+ added = p -> two -> size ;
1089+ diff_free_filespec_data (p -> two );
1090+ } else
10611091 continue ;
1062- changed += data -> files [i ]-> added ;
1063- changed += data -> files [i ]-> deleted ;
1092+
1093+ /*
1094+ * Original minus copied is the removed material,
1095+ * added is the new material. They are both damages
1096+ * made to the preimage.
1097+ */
1098+ damage = (p -> one -> size - copied ) + added ;
1099+
1100+ ALLOC_GROW (dir .files , dir .nr + 1 , dir .alloc );
1101+ dir .files [dir .nr ].name = name ;
1102+ dir .files [dir .nr ].changed = damage ;
1103+ changed += damage ;
1104+ dir .nr ++ ;
10641105 }
10651106
10661107 /* This can happen even with many files, if everything was renames */
10671108 if (!changed )
10681109 return ;
10691110
10701111 /* Show all directories with more than x% of the changes */
1071- dir .files = data -> files ;
1072- dir .nr = data -> nr ;
1073- dir .percent = options -> dirstat_percent ;
1074- dir .cumulative = options -> output_format & DIFF_FORMAT_CUMULATIVE ;
10751112 gather_dirstat (options -> file , & dir , changed , "" , 0 );
10761113}
10771114
@@ -3095,7 +3132,7 @@ void diff_flush(struct diff_options *options)
30953132 separator ++ ;
30963133 }
30973134
3098- if (output_format & (DIFF_FORMAT_DIFFSTAT |DIFF_FORMAT_SHORTSTAT |DIFF_FORMAT_NUMSTAT | DIFF_FORMAT_DIRSTAT )) {
3135+ if (output_format & (DIFF_FORMAT_DIFFSTAT |DIFF_FORMAT_SHORTSTAT |DIFF_FORMAT_NUMSTAT )) {
30993136 struct diffstat_t diffstat ;
31003137
31013138 memset (& diffstat , 0 , sizeof (struct diffstat_t ));
@@ -3105,8 +3142,6 @@ void diff_flush(struct diff_options *options)
31053142 if (check_pair_status (p ))
31063143 diff_flush_stat (p , options , & diffstat );
31073144 }
3108- if (output_format & DIFF_FORMAT_DIRSTAT )
3109- show_dirstat (& diffstat , options );
31103145 if (output_format & DIFF_FORMAT_NUMSTAT )
31113146 show_numstat (& diffstat , options );
31123147 if (output_format & DIFF_FORMAT_DIFFSTAT )
@@ -3116,6 +3151,8 @@ void diff_flush(struct diff_options *options)
31163151 free_diffstat_info (& diffstat );
31173152 separator ++ ;
31183153 }
3154+ if (output_format & DIFF_FORMAT_DIRSTAT )
3155+ show_dirstat (options );
31193156
31203157 if (output_format & DIFF_FORMAT_SUMMARY && !is_summary_empty (q )) {
31213158 for (i = 0 ; i < q -> nr ; i ++ )
0 commit comments