2020#include "mailmap.h"
2121#include "parse-options.h"
2222#include "utf8.h"
23+ #include "userdiff.h"
2324
2425static char blame_usage [] = "git blame [options] [rev-opts] [rev] [--] file" ;
2526
@@ -85,17 +86,51 @@ struct origin {
8586 char path [FLEX_ARRAY ];
8687};
8788
89+ /*
90+ * Prepare diff_filespec and convert it using diff textconv API
91+ * if the textconv driver exists.
92+ * Return 1 if the conversion succeeds, 0 otherwise.
93+ */
94+ static int textconv_object (const char * path ,
95+ const unsigned char * sha1 ,
96+ char * * buf ,
97+ unsigned long * buf_size )
98+ {
99+ struct diff_filespec * df ;
100+ struct userdiff_driver * textconv ;
101+
102+ df = alloc_filespec (path );
103+ fill_filespec (df , sha1 , S_IFREG | 0664 );
104+ textconv = get_textconv (df );
105+ if (!textconv ) {
106+ free_filespec (df );
107+ return 0 ;
108+ }
109+
110+ * buf_size = fill_textconv (textconv , df , buf );
111+ free_filespec (df );
112+ return 1 ;
113+ }
114+
88115/*
89116 * Given an origin, prepare mmfile_t structure to be used by the
90117 * diff machinery
91118 */
92- static void fill_origin_blob (struct origin * o , mmfile_t * file )
119+ static void fill_origin_blob (struct diff_options * opt ,
120+ struct origin * o , mmfile_t * file )
93121{
94122 if (!o -> file .ptr ) {
95123 enum object_type type ;
124+ unsigned long file_size ;
125+
96126 num_read_blob ++ ;
97- file -> ptr = read_sha1_file (o -> blob_sha1 , & type ,
98- (unsigned long * )(& (file -> size )));
127+ if (DIFF_OPT_TST (opt , ALLOW_TEXTCONV ) &&
128+ textconv_object (o -> path , o -> blob_sha1 , & file -> ptr , & file_size ))
129+ ;
130+ else
131+ file -> ptr = read_sha1_file (o -> blob_sha1 , & type , & file_size );
132+ file -> size = file_size ;
133+
99134 if (!file -> ptr )
100135 die ("Cannot read blob %s for path %s" ,
101136 sha1_to_hex (o -> blob_sha1 ),
@@ -282,7 +317,6 @@ static struct origin *get_origin(struct scoreboard *sb,
282317static int fill_blob_sha1 (struct origin * origin )
283318{
284319 unsigned mode ;
285-
286320 if (!is_null_sha1 (origin -> blob_sha1 ))
287321 return 0 ;
288322 if (get_tree_entry (origin -> commit -> object .sha1 ,
@@ -742,8 +776,8 @@ static int pass_blame_to_parent(struct scoreboard *sb,
742776 if (last_in_target < 0 )
743777 return 1 ; /* nothing remains for this target */
744778
745- fill_origin_blob (parent , & file_p );
746- fill_origin_blob (target , & file_o );
779+ fill_origin_blob (& sb -> revs -> diffopt , parent , & file_p );
780+ fill_origin_blob (& sb -> revs -> diffopt , target , & file_o );
747781 num_get_patch ++ ;
748782
749783 memset (& xpp , 0 , sizeof (xpp ));
@@ -924,7 +958,7 @@ static int find_move_in_parent(struct scoreboard *sb,
924958 if (last_in_target < 0 )
925959 return 1 ; /* nothing remains for this target */
926960
927- fill_origin_blob (parent , & file_p );
961+ fill_origin_blob (& sb -> revs -> diffopt , parent , & file_p );
928962 if (!file_p .ptr )
929963 return 0 ;
930964
@@ -1065,7 +1099,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
10651099
10661100 norigin = get_origin (sb , parent , p -> one -> path );
10671101 hashcpy (norigin -> blob_sha1 , p -> one -> sha1 );
1068- fill_origin_blob (norigin , & file_p );
1102+ fill_origin_blob (& sb -> revs -> diffopt , norigin , & file_p );
10691103 if (!file_p .ptr )
10701104 continue ;
10711105
@@ -1985,14 +2019,26 @@ static int git_blame_config(const char *var, const char *value, void *cb)
19852019 blame_date_mode = parse_date_format (value );
19862020 return 0 ;
19872021 }
2022+
2023+ switch (userdiff_config (var , value )) {
2024+ case 0 :
2025+ break ;
2026+ case -1 :
2027+ return -1 ;
2028+ default :
2029+ return 0 ;
2030+ }
2031+
19882032 return git_default_config (var , value , cb );
19892033}
19902034
19912035/*
19922036 * Prepare a dummy commit that represents the work tree (or staged) item.
19932037 * Note that annotating work tree item never works in the reverse.
19942038 */
1995- static struct commit * fake_working_tree_commit (const char * path , const char * contents_from )
2039+ static struct commit * fake_working_tree_commit (struct diff_options * opt ,
2040+ const char * path ,
2041+ const char * contents_from )
19962042{
19972043 struct commit * commit ;
19982044 struct origin * origin ;
@@ -2020,6 +2066,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
20202066 if (!contents_from || strcmp ("-" , contents_from )) {
20212067 struct stat st ;
20222068 const char * read_from ;
2069+ unsigned long buf_len ;
20232070
20242071 if (contents_from ) {
20252072 if (stat (contents_from , & st ) < 0 )
@@ -2032,9 +2079,13 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
20322079 read_from = path ;
20332080 }
20342081 mode = canon_mode (st .st_mode );
2082+
20352083 switch (st .st_mode & S_IFMT ) {
20362084 case S_IFREG :
2037- if (strbuf_read_file (& buf , read_from , st .st_size ) != st .st_size )
2085+ if (DIFF_OPT_TST (opt , ALLOW_TEXTCONV ) &&
2086+ textconv_object (read_from , null_sha1 , & buf .buf , & buf_len ))
2087+ buf .len = buf_len ;
2088+ else if (strbuf_read_file (& buf , read_from , st .st_size ) != st .st_size )
20382089 die_errno ("cannot open or read '%s'" , read_from );
20392090 break ;
20402091 case S_IFLNK :
@@ -2250,6 +2301,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
22502301 git_config (git_blame_config , NULL );
22512302 init_revisions (& revs , NULL );
22522303 revs .date_mode = blame_date_mode ;
2304+ DIFF_OPT_SET (& revs .diffopt , ALLOW_TEXTCONV );
22532305
22542306 save_commit_buffer = 0 ;
22552307 dashdash_pos = 0 ;
@@ -2386,7 +2438,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
23862438 * or "--contents".
23872439 */
23882440 setup_work_tree ();
2389- sb .final = fake_working_tree_commit (path , contents_from );
2441+ sb .final = fake_working_tree_commit (& sb .revs -> diffopt ,
2442+ path , contents_from );
23902443 add_pending_object (& revs , & (sb .final -> object ), ":" );
23912444 }
23922445 else if (contents_from )
@@ -2413,8 +2466,14 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
24132466 if (fill_blob_sha1 (o ))
24142467 die ("no such path %s in %s" , path , final_commit_name );
24152468
2416- sb .final_buf = read_sha1_file (o -> blob_sha1 , & type ,
2417- & sb .final_buf_size );
2469+ if (DIFF_OPT_TST (& sb .revs -> diffopt , ALLOW_TEXTCONV ) &&
2470+ textconv_object (path , o -> blob_sha1 , (char * * ) & sb .final_buf ,
2471+ & sb .final_buf_size ))
2472+ ;
2473+ else
2474+ sb .final_buf = read_sha1_file (o -> blob_sha1 , & type ,
2475+ & sb .final_buf_size );
2476+
24182477 if (!sb .final_buf )
24192478 die ("Cannot read blob %s for path %s" ,
24202479 sha1_to_hex (o -> blob_sha1 ),
0 commit comments