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 ,
@@ -741,8 +775,8 @@ static int pass_blame_to_parent(struct scoreboard *sb,
741775 if (last_in_target < 0 )
742776 return 1 ; /* nothing remains for this target */
743777
744- fill_origin_blob (parent , & file_p );
745- fill_origin_blob (target , & file_o );
778+ fill_origin_blob (& sb -> revs -> diffopt , parent , & file_p );
779+ fill_origin_blob (& sb -> revs -> diffopt , target , & file_o );
746780 num_get_patch ++ ;
747781
748782 memset (& xpp , 0 , sizeof (xpp ));
@@ -922,7 +956,7 @@ static int find_move_in_parent(struct scoreboard *sb,
922956 if (last_in_target < 0 )
923957 return 1 ; /* nothing remains for this target */
924958
925- fill_origin_blob (parent , & file_p );
959+ fill_origin_blob (& sb -> revs -> diffopt , parent , & file_p );
926960 if (!file_p .ptr )
927961 return 0 ;
928962
@@ -1063,7 +1097,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
10631097
10641098 norigin = get_origin (sb , parent , p -> one -> path );
10651099 hashcpy (norigin -> blob_sha1 , p -> one -> sha1 );
1066- fill_origin_blob (norigin , & file_p );
1100+ fill_origin_blob (& sb -> revs -> diffopt , norigin , & file_p );
10671101 if (!file_p .ptr )
10681102 continue ;
10691103
@@ -1983,14 +2017,26 @@ static int git_blame_config(const char *var, const char *value, void *cb)
19832017 blame_date_mode = parse_date_format (value );
19842018 return 0 ;
19852019 }
2020+
2021+ switch (userdiff_config (var , value )) {
2022+ case 0 :
2023+ break ;
2024+ case -1 :
2025+ return -1 ;
2026+ default :
2027+ return 0 ;
2028+ }
2029+
19862030 return git_default_config (var , value , cb );
19872031}
19882032
19892033/*
19902034 * Prepare a dummy commit that represents the work tree (or staged) item.
19912035 * Note that annotating work tree item never works in the reverse.
19922036 */
1993- static struct commit * fake_working_tree_commit (const char * path , const char * contents_from )
2037+ static struct commit * fake_working_tree_commit (struct diff_options * opt ,
2038+ const char * path ,
2039+ const char * contents_from )
19942040{
19952041 struct commit * commit ;
19962042 struct origin * origin ;
@@ -2018,6 +2064,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
20182064 if (!contents_from || strcmp ("-" , contents_from )) {
20192065 struct stat st ;
20202066 const char * read_from ;
2067+ unsigned long buf_len ;
20212068
20222069 if (contents_from ) {
20232070 if (stat (contents_from , & st ) < 0 )
@@ -2030,9 +2077,13 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
20302077 read_from = path ;
20312078 }
20322079 mode = canon_mode (st .st_mode );
2080+
20332081 switch (st .st_mode & S_IFMT ) {
20342082 case S_IFREG :
2035- if (strbuf_read_file (& buf , read_from , st .st_size ) != st .st_size )
2083+ if (DIFF_OPT_TST (opt , ALLOW_TEXTCONV ) &&
2084+ textconv_object (read_from , null_sha1 , & buf .buf , & buf_len ))
2085+ buf .len = buf_len ;
2086+ else if (strbuf_read_file (& buf , read_from , st .st_size ) != st .st_size )
20362087 die_errno ("cannot open or read '%s'" , read_from );
20372088 break ;
20382089 case S_IFLNK :
@@ -2248,6 +2299,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
22482299 git_config (git_blame_config , NULL );
22492300 init_revisions (& revs , NULL );
22502301 revs .date_mode = blame_date_mode ;
2302+ DIFF_OPT_SET (& revs .diffopt , ALLOW_TEXTCONV );
22512303
22522304 save_commit_buffer = 0 ;
22532305 dashdash_pos = 0 ;
@@ -2384,7 +2436,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
23842436 * or "--contents".
23852437 */
23862438 setup_work_tree ();
2387- sb .final = fake_working_tree_commit (path , contents_from );
2439+ sb .final = fake_working_tree_commit (& sb .revs -> diffopt ,
2440+ path , contents_from );
23882441 add_pending_object (& revs , & (sb .final -> object ), ":" );
23892442 }
23902443 else if (contents_from )
@@ -2411,8 +2464,14 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
24112464 if (fill_blob_sha1 (o ))
24122465 die ("no such path %s in %s" , path , final_commit_name );
24132466
2414- sb .final_buf = read_sha1_file (o -> blob_sha1 , & type ,
2415- & sb .final_buf_size );
2467+ if (DIFF_OPT_TST (& sb .revs -> diffopt , ALLOW_TEXTCONV ) &&
2468+ textconv_object (path , o -> blob_sha1 , (char * * ) & sb .final_buf ,
2469+ & sb .final_buf_size ))
2470+ ;
2471+ else
2472+ sb .final_buf = read_sha1_file (o -> blob_sha1 , & type ,
2473+ & sb .final_buf_size );
2474+
24162475 if (!sb .final_buf )
24172476 die ("Cannot read blob %s for path %s" ,
24182477 sha1_to_hex (o -> blob_sha1 ),
0 commit comments