44#include "diff.h"
55#include "diffcore.h"
66#include "quote.h"
7+ #include "xdiff/xdiff.h"
78
89static int uninteresting (struct diff_filepair * p )
910{
@@ -110,28 +111,6 @@ static char *grab_blob(const unsigned char *sha1, unsigned long *size)
110111 return blob ;
111112}
112113
113- #define TMPPATHLEN 50
114- #define MAXLINELEN 10240
115-
116- static void write_to_temp_file (char * tmpfile , void * blob , unsigned long size )
117- {
118- int fd = git_mkstemp (tmpfile , TMPPATHLEN , ".diff_XXXXXX" );
119- if (fd < 0 )
120- die ("unable to create temp-file" );
121- if (write (fd , blob , size ) != size )
122- die ("unable to write temp-file" );
123- close (fd );
124- }
125-
126- static void write_temp_blob (char * tmpfile , const unsigned char * sha1 )
127- {
128- unsigned long size ;
129- void * blob ;
130- blob = grab_blob (sha1 , & size );
131- write_to_temp_file (tmpfile , blob , size );
132- free (blob );
133- }
134-
135114static int parse_num (char * * cp_p , unsigned int * num_p )
136115{
137116 char * cp = * cp_p ;
@@ -178,10 +157,9 @@ static int parse_hunk_header(char *line, int len,
178157 return - !!memcmp (cp , " @@" , 3 );
179158}
180159
181- static void append_lost (struct sline * sline , int n , const char * line )
160+ static void append_lost (struct sline * sline , int n , const char * line , int len )
182161{
183162 struct lline * lline ;
184- int len = strlen (line );
185163 unsigned long this_mask = (1UL <<n );
186164 if (line [len - 1 ] == '\n' )
187165 len -- ;
@@ -216,70 +194,130 @@ static void append_lost(struct sline *sline, int n, const char *line)
216194 sline -> lost_tail = & lline -> next ;
217195}
218196
219- static void combine_diff (const unsigned char * parent , const char * ourtmp ,
197+ struct combine_diff_state {
198+ char * remainder ;
199+ unsigned long remainder_size ;
200+ unsigned int lno , ob , on , nb , nn ;
201+ unsigned long nmask ;
202+ int num_parent ;
203+ int n ;
204+ struct sline * sline ;
205+ struct sline * lost_bucket ;
206+ };
207+
208+ static void consume_line (struct combine_diff_state * state ,
209+ char * line ,
210+ unsigned long len )
211+ {
212+ if (5 < len && !memcmp ("@@ -" , line , 4 )) {
213+ if (parse_hunk_header (line , len ,
214+ & state -> ob , & state -> on ,
215+ & state -> nb , & state -> nn ))
216+ return ;
217+ state -> lno = state -> nb ;
218+ if (!state -> nb )
219+ /* @@ -1,2 +0,0 @@ to remove the
220+ * first two lines...
221+ */
222+ state -> nb = 1 ;
223+ if (state -> nn == 0 )
224+ /* @@ -X,Y +N,0 @@ removed Y lines
225+ * that would have come *after* line N
226+ * in the result. Our lost buckets hang
227+ * to the line after the removed lines,
228+ */
229+ state -> lost_bucket = & state -> sline [state -> nb ];
230+ else
231+ state -> lost_bucket = & state -> sline [state -> nb - 1 ];
232+ if (!state -> sline [state -> nb - 1 ].p_lno )
233+ state -> sline [state -> nb - 1 ].p_lno =
234+ xcalloc (state -> num_parent ,
235+ sizeof (unsigned long ));
236+ state -> sline [state -> nb - 1 ].p_lno [state -> n ] = state -> ob ;
237+ return ;
238+ }
239+ if (!state -> lost_bucket )
240+ return ; /* not in any hunk yet */
241+ switch (line [0 ]) {
242+ case '-' :
243+ append_lost (state -> lost_bucket , state -> n , line + 1 , len - 1 );
244+ break ;
245+ case '+' :
246+ state -> sline [state -> lno - 1 ].flag |= state -> nmask ;
247+ state -> lno ++ ;
248+ break ;
249+ }
250+ }
251+
252+ static int combine_diff_outf (void * priv_ , mmbuffer_t * mb , int nbuf )
253+ {
254+ struct combine_diff_state * priv = priv_ ;
255+ int i ;
256+ for (i = 0 ; i < nbuf ; i ++ ) {
257+ if (mb [i ].ptr [mb [i ].size - 1 ] != '\n' ) {
258+ /* Incomplete line */
259+ priv -> remainder = realloc (priv -> remainder ,
260+ priv -> remainder_size +
261+ mb [i ].size );
262+ memcpy (priv -> remainder + priv -> remainder_size ,
263+ mb [i ].ptr , mb [i ].size );
264+ priv -> remainder_size += mb [i ].size ;
265+ continue ;
266+ }
267+
268+ /* we have a complete line */
269+ if (!priv -> remainder ) {
270+ consume_line (priv , mb [i ].ptr , mb [i ].size );
271+ continue ;
272+ }
273+ priv -> remainder = realloc (priv -> remainder ,
274+ priv -> remainder_size +
275+ mb [i ].size );
276+ memcpy (priv -> remainder + priv -> remainder_size ,
277+ mb [i ].ptr , mb [i ].size );
278+ consume_line (priv , priv -> remainder ,
279+ priv -> remainder_size + mb [i ].size );
280+ free (priv -> remainder );
281+ priv -> remainder = NULL ;
282+ priv -> remainder_size = 0 ;
283+ }
284+ return 0 ;
285+ }
286+
287+ static void combine_diff (const unsigned char * parent , mmfile_t * result_file ,
220288 struct sline * sline , int cnt , int n , int num_parent )
221289{
222- FILE * in ;
223- char parent_tmp [TMPPATHLEN ];
224- char cmd [TMPPATHLEN * 2 + 1024 ];
225- char line [MAXLINELEN ];
226- unsigned int lno , ob , on , nb , nn , p_lno ;
290+ unsigned int p_lno , lno ;
227291 unsigned long nmask = (1UL << n );
228- struct sline * lost_bucket = NULL ;
292+ xpparam_t xpp ;
293+ xdemitconf_t xecfg ;
294+ mmfile_t parent_file ;
295+ xdemitcb_t ecb ;
296+ struct combine_diff_state state ;
297+ unsigned long sz ;
229298
230299 if (!cnt )
231300 return ; /* result deleted */
232301
233- write_temp_blob (parent_tmp , parent );
234- sprintf (cmd , "diff --unified=0 -La/x -Lb/x '%s' '%s'" ,
235- parent_tmp , ourtmp );
236- in = popen (cmd , "r" );
237- if (!in )
238- die ("cannot spawn %s" , cmd );
239-
240- lno = 1 ;
241- while (fgets (line , sizeof (line ), in ) != NULL ) {
242- int len = strlen (line );
243- if (5 < len && !memcmp ("@@ -" , line , 4 )) {
244- if (parse_hunk_header (line , len ,
245- & ob , & on , & nb , & nn ))
246- break ;
247- lno = nb ;
248- if (!nb )
249- /* @@ -1,2 +0,0 @@ to remove the
250- * first two lines...
251- */
252- nb = 1 ;
253- if (nn == 0 )
254- /* @@ -X,Y +N,0 @@ removed Y lines
255- * that would have come *after* line N
256- * in the result. Our lost buckets hang
257- * to the line after the removed lines,
258- */
259- lost_bucket = & sline [nb ];
260- else
261- lost_bucket = & sline [nb - 1 ];
262- if (!sline [nb - 1 ].p_lno )
263- sline [nb - 1 ].p_lno =
264- xcalloc (num_parent ,
265- sizeof (unsigned long ));
266- sline [nb - 1 ].p_lno [n ] = ob ;
267- continue ;
268- }
269- if (!lost_bucket )
270- continue ; /* not in any hunk yet */
271- switch (line [0 ]) {
272- case '-' :
273- append_lost (lost_bucket , n , line + 1 );
274- break ;
275- case '+' :
276- sline [lno - 1 ].flag |= nmask ;
277- lno ++ ;
278- break ;
279- }
280- }
281- fclose (in );
282- unlink (parent_tmp );
302+ parent_file .ptr = grab_blob (parent , & sz );
303+ parent_file .size = sz ;
304+ xpp .flags = XDF_NEED_MINIMAL ;
305+ xecfg .ctxlen = 0 ;
306+ xecfg .flags = 0 ;
307+ ecb .outf = combine_diff_outf ;
308+ ecb .priv = & state ;
309+ memset (& state , 0 , sizeof (state ));
310+ state .nmask = nmask ;
311+ state .sline = sline ;
312+ state .lno = 1 ;
313+ state .num_parent = num_parent ;
314+ state .n = n ;
315+
316+ xdl_diff (& parent_file , result_file , & xpp , & xecfg , & ecb );
317+ if (state .remainder && state .remainder_size )
318+ consume_line (& state , state .remainder , state .remainder_size );
319+ free (state .remainder );
320+ free (parent_file .ptr );
283321
284322 /* Assign line numbers for this parent.
285323 *
@@ -625,61 +663,56 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
625663 int dense , const char * header ,
626664 struct diff_options * opt )
627665{
628- unsigned long size , cnt , lno ;
666+ unsigned long result_size , cnt , lno ;
629667 char * result , * cp , * ep ;
630668 struct sline * sline ; /* survived lines */
631669 int mode_differs = 0 ;
632670 int i , show_hunks , shown_header = 0 ;
633- char ourtmp_buf [TMPPATHLEN ];
634- char * ourtmp = ourtmp_buf ;
635671 int working_tree_file = !memcmp (elem -> sha1 , null_sha1 , 20 );
636672 int abbrev = opt -> full_index ? 40 : DEFAULT_ABBREV ;
673+ mmfile_t result_file ;
637674
638675 /* Read the result of merge first */
639- if (!working_tree_file ) {
640- result = grab_blob (elem -> sha1 , & size );
641- write_to_temp_file (ourtmp , result , size );
642- }
676+ if (!working_tree_file )
677+ result = grab_blob (elem -> sha1 , & result_size );
643678 else {
644679 /* Used by diff-tree to read from the working tree */
645680 struct stat st ;
646681 int fd ;
647- ourtmp = elem -> path ;
648- if (0 <= (fd = open (ourtmp , O_RDONLY )) &&
682+ if (0 <= (fd = open (elem -> path , O_RDONLY )) &&
649683 !fstat (fd , & st )) {
650684 int len = st .st_size ;
651685 int cnt = 0 ;
652686
653687 elem -> mode = canon_mode (st .st_mode );
654- size = len ;
688+ result_size = len ;
655689 result = xmalloc (len + 1 );
656690 while (cnt < len ) {
657691 int done = xread (fd , result + cnt , len - cnt );
658692 if (done == 0 )
659693 break ;
660694 if (done < 0 )
661- die ("read error '%s'" , ourtmp );
695+ die ("read error '%s'" , elem -> path );
662696 cnt += done ;
663697 }
664698 result [len ] = 0 ;
665699 }
666700 else {
667701 /* deleted file */
668- size = 0 ;
702+ result_size = 0 ;
669703 elem -> mode = 0 ;
670704 result = xmalloc (1 );
671705 result [0 ] = 0 ;
672- ourtmp = "/dev/null" ;
673706 }
674707 if (0 <= fd )
675708 close (fd );
676709 }
677710
678- for (cnt = 0 , cp = result ; cp - result < size ; cp ++ ) {
711+ for (cnt = 0 , cp = result ; cp - result < result_size ; cp ++ ) {
679712 if (* cp == '\n' )
680713 cnt ++ ;
681714 }
682- if (size && result [size - 1 ] != '\n' )
715+ if (result_size && result [result_size - 1 ] != '\n' )
683716 cnt ++ ; /* incomplete line */
684717
685718 sline = xcalloc (cnt + 1 , sizeof (* sline ));
@@ -689,16 +722,19 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
689722 sline [lno ].lost_tail = & sline [lno ].lost_head ;
690723 sline [lno ].flag = 0 ;
691724 }
692- for (lno = 0 , cp = result ; cp - result < size ; cp ++ ) {
725+ for (lno = 0 , cp = result ; cp - result < result_size ; cp ++ ) {
693726 if (* cp == '\n' ) {
694727 sline [lno ].len = cp - sline [lno ].bol ;
695728 lno ++ ;
696729 if (lno < cnt )
697730 sline [lno ].bol = cp + 1 ;
698731 }
699732 }
700- if (size && result [size - 1 ] != '\n' )
701- sline [cnt - 1 ].len = size - (sline [cnt - 1 ].bol - result );
733+ if (result_size && result [result_size - 1 ] != '\n' )
734+ sline [cnt - 1 ].len = result_size - (sline [cnt - 1 ].bol - result );
735+
736+ result_file .ptr = result ;
737+ result_file .size = result_size ;
702738
703739 sline [0 ].p_lno = xcalloc ((cnt + 1 ) * num_parent , sizeof (unsigned long ));
704740 for (lno = 0 ; lno < cnt ; lno ++ )
@@ -714,7 +750,7 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
714750 }
715751 }
716752 if (i <= j )
717- combine_diff (elem -> parent [i ].sha1 , ourtmp , sline ,
753+ combine_diff (elem -> parent [i ].sha1 , & result_file , sline ,
718754 cnt , i , num_parent );
719755 if (elem -> parent [i ].mode != elem -> mode )
720756 mode_differs = 1 ;
@@ -767,8 +803,6 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
767803 }
768804 dump_sline (sline , cnt , num_parent );
769805 }
770- if (ourtmp == ourtmp_buf )
771- unlink (ourtmp );
772806 free (result );
773807
774808 for (i = 0 ; i < cnt ; i ++ ) {
0 commit comments