@@ -939,7 +939,7 @@ static FILE *do_convert (FILE *f, const char *mode, int seekable,
939939 error (EXIT_FAILURE , errno , "fdopen failed" );
940940
941941 if (seekable ) {
942- FILE * tmp = xtmpfile ();
942+ FILE * tmp = xtmpfile ();
943943 while (!feof (ret )) {
944944 int c = fgetc (ret );
945945
@@ -1112,3 +1112,118 @@ filename_from_header (const char *header)
11121112
11131113 return xstrndup (header , h );
11141114}
1115+
1116+ enum git_diff_type
1117+ detect_git_diff_type (char * * headers , unsigned int num_headers )
1118+ {
1119+ unsigned int i ;
1120+ int has_similarity_100 = 0 ;
1121+ int has_rename = 0 ;
1122+ int has_binary = 0 ;
1123+ int has_mode_change = 0 ;
1124+ int has_new_file = 0 ;
1125+ int has_deleted_file = 0 ;
1126+
1127+ /* Check if this is even a git diff */
1128+ if (num_headers == 0 || strncmp (headers [0 ], "diff --git " , 11 ))
1129+ return GIT_DIFF_NORMAL ;
1130+
1131+ /* Analyze the headers */
1132+ for (i = 0 ; i < num_headers ; i ++ ) {
1133+ if (!strncmp (headers [i ], "similarity index 100%" , 21 ))
1134+ has_similarity_100 = 1 ;
1135+ else if (!strncmp (headers [i ], "rename from " , 12 ) ||
1136+ !strncmp (headers [i ], "rename to " , 10 ))
1137+ has_rename = 1 ;
1138+ else if (!strncmp (headers [i ], "old mode " , 9 ) ||
1139+ !strncmp (headers [i ], "new mode " , 9 ))
1140+ has_mode_change = 1 ;
1141+ else if (!strncmp (headers [i ], "new file mode " , 14 ))
1142+ has_new_file = 1 ;
1143+ else if (!strncmp (headers [i ], "deleted file mode " , 18 ))
1144+ has_deleted_file = 1 ;
1145+ else if (strstr (headers [i ], "Binary files " ) ||
1146+ !strncmp (headers [i ], "GIT binary patch" , 16 ))
1147+ has_binary = 1 ;
1148+ }
1149+
1150+ /* Determine the type based on header combinations */
1151+ if (has_similarity_100 && has_rename )
1152+ return GIT_DIFF_RENAME ;
1153+ else if (has_binary )
1154+ return GIT_DIFF_BINARY ;
1155+ else if (has_mode_change && !has_new_file && !has_deleted_file )
1156+ return GIT_DIFF_MODE_ONLY ;
1157+ else if (has_new_file )
1158+ return GIT_DIFF_NEW_FILE ;
1159+ else if (has_deleted_file )
1160+ return GIT_DIFF_DELETED_FILE ;
1161+ else
1162+ return GIT_DIFF_NORMAL ;
1163+ }
1164+
1165+ int
1166+ extract_git_filenames (char * * headers , unsigned int num_headers ,
1167+ char * * old_name , char * * new_name )
1168+ {
1169+ unsigned int i ;
1170+ char * git_line = NULL ;
1171+ char * rename_from = NULL , * rename_to = NULL ;
1172+
1173+ * old_name = NULL ;
1174+ * new_name = NULL ;
1175+
1176+ /* Find the diff --git line */
1177+ for (i = 0 ; i < num_headers ; i ++ ) {
1178+ if (!strncmp (headers [i ], "diff --git " , 11 )) {
1179+ git_line = headers [i ];
1180+ break ;
1181+ }
1182+ }
1183+
1184+ if (!git_line )
1185+ return 1 ; /* Not a git diff */
1186+
1187+ /* Look for rename headers first */
1188+ for (i = 0 ; i < num_headers ; i ++ ) {
1189+ if (!strncmp (headers [i ], "rename from " , 12 ))
1190+ rename_from = headers [i ] + 12 ;
1191+ else if (!strncmp (headers [i ], "rename to " , 10 ))
1192+ rename_to = headers [i ] + 10 ;
1193+ }
1194+
1195+ if (rename_from && rename_to ) {
1196+ /* Use rename headers for filenames */
1197+ * old_name = xstrndup (rename_from , strcspn (rename_from , "\n\r" ));
1198+ * new_name = xstrndup (rename_to , strcspn (rename_to , "\n\r" ));
1199+ } else {
1200+ /* Parse filenames from "diff --git a/path b/path" line */
1201+ char * p = git_line + 11 ; /* Skip "diff --git " */
1202+ char * space1 , * space2 ;
1203+
1204+ /* Find the space between a/path and b/path */
1205+ space1 = strchr (p , ' ' );
1206+ if (!space1 )
1207+ return 1 ;
1208+
1209+ /* Extract old filename, stripping a/ prefix if present */
1210+ if (space1 - p > 2 && p [0 ] == 'a' && p [1 ] == '/' ) {
1211+ * old_name = xstrndup (p + 2 , space1 - p - 2 );
1212+ } else {
1213+ * old_name = xstrndup (p , space1 - p );
1214+ }
1215+
1216+ /* Find start of new filename (b/path) */
1217+ space2 = space1 + 1 ;
1218+
1219+ /* Extract new filename, stripping b/ prefix if present */
1220+ size_t new_len = strcspn (space2 , "\n\r" );
1221+ if (new_len > 2 && space2 [0 ] == 'b' && space2 [1 ] == '/' ) {
1222+ * new_name = xstrndup (space2 + 2 , new_len - 2 );
1223+ } else {
1224+ * new_name = xstrndup (space2 , new_len );
1225+ }
1226+ }
1227+
1228+ return 0 ;
1229+ }
0 commit comments