2 #include "run-command.h"
3 #include "xdiff-interface.h"
6 static void rm_temp_file(const char *filename
)
9 free((void *)filename
);
12 static const char *write_temp_file(mmfile_t
*f
)
15 const char *tmp
= getenv("TMPDIR");
20 filename
= mkpath("%s/%s", tmp
, "git-tmp-XXXXXX");
21 fd
= mkstemp(filename
);
24 filename
= xstrdup(filename
);
25 if (f
->size
!= xwrite(fd
, f
->ptr
, f
->size
)) {
26 rm_temp_file(filename
);
33 static void *read_temp_file(const char *filename
, unsigned long *size
)
37 int fd
= open(filename
, O_RDONLY
);
40 if (!fstat(fd
, &st
)) {
42 buf
= xmalloc(st
.st_size
);
43 if (st
.st_size
!= xread(fd
, buf
, st
.st_size
)) {
52 static int fill_mmfile_blob(mmfile_t
*f
, struct blob
*obj
)
58 buf
= read_sha1_file(obj
->object
.sha1
, type
, &size
);
61 if (strcmp(type
, blob_type
))
68 static void free_mmfile(mmfile_t
*f
)
73 static void *three_way_filemerge(mmfile_t
*base
, mmfile_t
*our
, mmfile_t
*their
, unsigned long *size
)
76 const char *t1
, *t2
, *t3
;
78 t1
= write_temp_file(base
);
79 t2
= write_temp_file(our
);
80 t3
= write_temp_file(their
);
83 int code
= run_command("merge", t2
, t1
, t3
, NULL
);
84 if (!code
|| code
== -1)
85 res
= read_temp_file(t2
, size
);
93 static int common_outf(void *priv_
, mmbuffer_t
*mb
, int nbuf
)
96 mmfile_t
*dst
= priv_
;
98 for (i
= 0; i
< nbuf
; i
++) {
99 memcpy(dst
->ptr
+ dst
->size
, mb
[i
].ptr
, mb
[i
].size
);
100 dst
->size
+= mb
[i
].size
;
105 static int generate_common_file(mmfile_t
*res
, mmfile_t
*f1
, mmfile_t
*f2
)
107 unsigned long size
= f1
->size
< f2
->size
? f1
->size
: f2
->size
;
108 void *ptr
= xmalloc(size
);
113 xpp
.flags
= XDF_NEED_MINIMAL
;
115 xecfg
.flags
= XDL_EMIT_COMMON
;
116 ecb
.outf
= common_outf
;
122 return xdl_diff(f1
, f2
, &xpp
, &xecfg
, &ecb
);
125 void *merge_file(struct blob
*base
, struct blob
*our
, struct blob
*their
, unsigned long *size
)
128 mmfile_t f1
, f2
, common
;
131 * Removed in either branch?
133 * NOTE! This depends on the caller having done the
134 * proper warning about removing a file that got
135 * modified in the other branch!
137 if (!our
|| !their
) {
143 return read_sha1_file(our
->object
.sha1
, type
, size
);
146 if (fill_mmfile_blob(&f1
, our
) < 0)
148 if (fill_mmfile_blob(&f2
, their
) < 0)
152 if (fill_mmfile_blob(&common
, base
) < 0)
155 if (generate_common_file(&common
, &f1
, &f2
) < 0)
158 res
= three_way_filemerge(&common
, &f1
, &f2
, size
);
159 free_mmfile(&common
);