1616#include "diff.h"
1717#include "diffcore.h"
1818#include "revision.h"
19+ #include "xdiff-interface.h"
1920
2021#define DEBUG 0
2122
@@ -57,116 +58,89 @@ static int num_get_patch = 0;
5758static int num_commits = 0 ;
5859static int patch_time = 0 ;
5960
60- #define TEMPFILE_PATH_LEN 60
61- static struct patch * get_patch (struct commit * commit , struct commit * other )
62- {
61+ struct blame_diff_state {
62+ struct xdiff_emit_state xm ;
6363 struct patch * ret ;
64- struct util_info * info_c = (struct util_info * )commit -> object .util ;
65- struct util_info * info_o = (struct util_info * )other -> object .util ;
66- char tmp_path1 [TEMPFILE_PATH_LEN ], tmp_path2 [TEMPFILE_PATH_LEN ];
67- char diff_cmd [TEMPFILE_PATH_LEN * 2 + 20 ];
68- struct timeval tv_start , tv_end ;
69- int fd ;
70- FILE * fin ;
71- char buf [1024 ];
72-
73- ret = xmalloc (sizeof (struct patch ));
74- ret -> chunks = NULL ;
75- ret -> num = 0 ;
76-
77- get_blob (commit );
78- get_blob (other );
64+ };
7965
80- gettimeofday (& tv_start , NULL );
66+ static void process_u0_diff (void * state_ , char * line , unsigned long len )
67+ {
68+ struct blame_diff_state * state = state_ ;
69+ struct chunk * chunk ;
8170
82- fd = git_mkstemp (tmp_path1 , TEMPFILE_PATH_LEN , "git-blame-XXXXXX" );
83- if (fd < 0 )
84- die ("unable to create temp-file: %s" , strerror (errno ));
71+ if (len < 4 || line [0 ] != '@' || line [1 ] != '@' )
72+ return ;
8573
86- if (xwrite (fd , info_c -> buf , info_c -> size ) != info_c -> size )
87- die ("write failed: %s" , strerror (errno ));
88- close (fd );
74+ if (DEBUG )
75+ printf ("chunk line: %.*s" , (int )len , line );
76+ state -> ret -> num ++ ;
77+ state -> ret -> chunks = xrealloc (state -> ret -> chunks ,
78+ sizeof (struct chunk ) * state -> ret -> num );
79+ chunk = & state -> ret -> chunks [state -> ret -> num - 1 ];
80+
81+ assert (!strncmp (line , "@@ -" , 4 ));
82+
83+ if (parse_hunk_header (line , len ,
84+ & chunk -> off1 , & chunk -> len1 ,
85+ & chunk -> off2 , & chunk -> len2 )) {
86+ state -> ret -> num -- ;
87+ return ;
88+ }
8989
90- fd = git_mkstemp (tmp_path2 , TEMPFILE_PATH_LEN , "git-blame-XXXXXX" );
91- if (fd < 0 )
92- die ("unable to create temp-file: %s" , strerror (errno ));
90+ if (chunk -> len1 == 0 )
91+ chunk -> off1 ++ ;
92+ if (chunk -> len2 == 0 )
93+ chunk -> off2 ++ ;
9394
94- if (xwrite (fd , info_o -> buf , info_o -> size ) != info_o -> size )
95- die ("write failed: %s" , strerror (errno ));
96- close (fd );
95+ if (chunk -> off1 > 0 )
96+ chunk -> off1 -- ;
97+ if (chunk -> off2 > 0 )
98+ chunk -> off2 -- ;
9799
98- sprintf (diff_cmd , "diff -U 0 %s %s" , tmp_path1 , tmp_path2 );
99- fin = popen (diff_cmd , "r" );
100- if (!fin )
101- die ("popen failed: %s" , strerror (errno ));
100+ assert (chunk -> off1 >= 0 );
101+ assert (chunk -> off2 >= 0 );
102+ }
102103
103- while (fgets (buf , sizeof (buf ), fin )) {
104- struct chunk * chunk ;
105- char * start , * sp ;
104+ static struct patch * get_patch (struct commit * commit , struct commit * other )
105+ {
106+ struct blame_diff_state state ;
107+ xpparam_t xpp ;
108+ xdemitconf_t xecfg ;
109+ mmfile_t file_c , file_o ;
110+ xdemitcb_t ecb ;
111+ struct util_info * info_c = (struct util_info * )commit -> object .util ;
112+ struct util_info * info_o = (struct util_info * )other -> object .util ;
113+ struct timeval tv_start , tv_end ;
106114
107- if (buf [0 ] != '@' || buf [1 ] != '@' )
108- continue ;
115+ get_blob (commit );
116+ file_c .ptr = info_c -> buf ;
117+ file_c .size = info_c -> size ;
109118
110- if (DEBUG )
111- printf ("chunk line: %s" , buf );
112- ret -> num ++ ;
113- ret -> chunks = xrealloc (ret -> chunks ,
114- sizeof (struct chunk ) * ret -> num );
115- chunk = & ret -> chunks [ret -> num - 1 ];
116-
117- assert (!strncmp (buf , "@@ -" , 4 ));
118-
119- start = buf + 4 ;
120- sp = index (start , ' ' );
121- * sp = '\0' ;
122- if (index (start , ',' )) {
123- int ret =
124- sscanf (start , "%d,%d" , & chunk -> off1 , & chunk -> len1 );
125- assert (ret == 2 );
126- } else {
127- int ret = sscanf (start , "%d" , & chunk -> off1 );
128- assert (ret == 1 );
129- chunk -> len1 = 1 ;
130- }
131- * sp = ' ' ;
132-
133- start = sp + 1 ;
134- sp = index (start , ' ' );
135- * sp = '\0' ;
136- if (index (start , ',' )) {
137- int ret =
138- sscanf (start , "%d,%d" , & chunk -> off2 , & chunk -> len2 );
139- assert (ret == 2 );
140- } else {
141- int ret = sscanf (start , "%d" , & chunk -> off2 );
142- assert (ret == 1 );
143- chunk -> len2 = 1 ;
144- }
145- * sp = ' ' ;
119+ get_blob (other );
120+ file_o .ptr = info_o -> buf ;
121+ file_o .size = info_o -> size ;
146122
147- if (chunk -> len1 == 0 )
148- chunk -> off1 ++ ;
149- if (chunk -> len2 == 0 )
150- chunk -> off2 ++ ;
123+ gettimeofday (& tv_start , NULL );
151124
152- if (chunk -> off1 > 0 )
153- chunk -> off1 -- ;
154- if (chunk -> off2 > 0 )
155- chunk -> off2 -- ;
125+ xpp .flags = XDF_NEED_MINIMAL ;
126+ xecfg .ctxlen = 0 ;
127+ xecfg .flags = 0 ;
128+ ecb .outf = xdiff_outf ;
129+ ecb .priv = & state ;
130+ memset (& state , 0 , sizeof (state ));
131+ state .xm .consume = process_u0_diff ;
132+ state .ret = xmalloc (sizeof (struct patch ));
133+ state .ret -> chunks = NULL ;
134+ state .ret -> num = 0 ;
156135
157- assert (chunk -> off1 >= 0 );
158- assert (chunk -> off2 >= 0 );
159- }
160- pclose (fin );
161- unlink (tmp_path1 );
162- unlink (tmp_path2 );
136+ xdl_diff (& file_c , & file_o , & xpp , & xecfg , & ecb );
163137
164138 gettimeofday (& tv_end , NULL );
165139 patch_time += 1000000 * (tv_end .tv_sec - tv_start .tv_sec ) +
166140 tv_end .tv_usec - tv_start .tv_usec ;
167141
168142 num_get_patch ++ ;
169- return ret ;
143+ return state . ret ;
170144}
171145
172146static void free_patch (struct patch * p )
@@ -674,7 +648,7 @@ static void get_commit_info(struct commit* commit, struct commit_info* ret)
674648 static char author_buf [1024 ];
675649
676650 tmp = strstr (commit -> buffer , "\nauthor " ) + 8 ;
677- len = index (tmp , '\n' ) - tmp ;
651+ len = strchr (tmp , '\n' ) - tmp ;
678652 ret -> author = author_buf ;
679653 memcpy (ret -> author , tmp , len );
680654
@@ -729,11 +703,30 @@ static void* topo_getter(struct commit* c)
729703 return util -> topo_data ;
730704}
731705
706+ static int read_ancestry (const char * graft_file ,
707+ unsigned char * * start_sha1 )
708+ {
709+ FILE * fp = fopen (graft_file , "r" );
710+ char buf [1024 ];
711+ if (!fp )
712+ return -1 ;
713+ while (fgets (buf , sizeof (buf ), fp )) {
714+ /* The format is just "Commit Parent1 Parent2 ...\n" */
715+ int len = strlen (buf );
716+ struct commit_graft * graft = read_graft_line (buf , len );
717+ register_commit_graft (graft , 0 );
718+ if (!* start_sha1 )
719+ * start_sha1 = graft -> sha1 ;
720+ }
721+ fclose (fp );
722+ return 0 ;
723+ }
724+
732725int main (int argc , const char * * argv )
733726{
734727 int i ;
735728 struct commit * initial = NULL ;
736- unsigned char sha1 [20 ];
729+ unsigned char sha1 [20 ], * sha1_p = NULL ;
737730
738731 const char * filename = NULL , * commit = NULL ;
739732 char filename_buf [256 ];
@@ -767,6 +760,14 @@ int main(int argc, const char **argv)
767760 !strcmp (argv [i ], "--compability" )) {
768761 compability = 1 ;
769762 continue ;
763+ } else if (!strcmp (argv [i ], "-S" )) {
764+ if (i + 1 < argc &&
765+ !read_ancestry (argv [i + 1 ], & sha1_p )) {
766+ compability = 1 ;
767+ i ++ ;
768+ continue ;
769+ }
770+ usage (blame_usage );
770771 } else if (!strcmp (argv [i ], "--" )) {
771772 options = 0 ;
772773 continue ;
@@ -788,7 +789,9 @@ int main(int argc, const char **argv)
788789
789790 if (!filename )
790791 usage (blame_usage );
791- if (!commit )
792+ if (commit && sha1_p )
793+ usage (blame_usage );
794+ else if (!commit )
792795 commit = "HEAD" ;
793796
794797 if (prefix )
@@ -797,9 +800,12 @@ int main(int argc, const char **argv)
797800 strcpy (filename_buf , filename );
798801 filename = filename_buf ;
799802
800- if (get_sha1 (commit , sha1 ))
801- die ("get_sha1 failed, commit '%s' not found" , commit );
802- start_commit = lookup_commit_reference (sha1 );
803+ if (!sha1_p ) {
804+ if (get_sha1 (commit , sha1 ))
805+ die ("get_sha1 failed, commit '%s' not found" , commit );
806+ sha1_p = sha1 ;
807+ }
808+ start_commit = lookup_commit_reference (sha1_p );
803809 get_util (start_commit )-> pathname = filename ;
804810 if (fill_util_info (start_commit )) {
805811 printf ("%s not found in %s\n" , filename , commit );
@@ -876,7 +882,7 @@ int main(int argc, const char **argv)
876882 if (blame_contents [blame_len - 1 ] != '\n' )
877883 putc ('\n' , stdout );
878884 } else {
879- char * next_buf = index (buf , '\n' ) + 1 ;
885+ char * next_buf = strchr (buf , '\n' ) + 1 ;
880886 fwrite (buf , next_buf - buf , 1 , stdout );
881887 buf = next_buf ;
882888 }
0 commit comments