20
#include "mailmap.h"
21
#include "parse-options.h"
22
#include "utf8.h"
23
+#include "userdiff.h"
24
25
static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file";
26
86
char path[FLEX_ARRAY];
87
};
88
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
+
115
/*
116
* Given an origin, prepare mmfile_t structure to be used by the
117
* diff machinery
118
*/
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)
121
{
122
if (!o->file.ptr) {
123
enum object_type type;
124
+ unsigned long file_size;
125
+
126
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
+
134
if (!file->ptr)
135
die("Cannot read blob %s for path %s",
136
sha1_to_hex(o->blob_sha1),
317
static int fill_blob_sha1(struct origin *origin)
318
{
319
unsigned mode;
285
-
320
if (!is_null_sha1(origin->blob_sha1))
321
return 0;
322
if (get_tree_entry(origin->commit->object.sha1,
775
if (last_in_target < 0)
776
return 1; /* nothing remains for this target */
777
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);
780
num_get_patch++;
781
782
memset(&xpp, 0, sizeof(xpp));
956
if (last_in_target < 0)
957
return 1; /* nothing remains for this target */
958
925
- fill_origin_blob(parent, &file_p);
959
+ fill_origin_blob(&sb->revs->diffopt, parent, &file_p);
960
if (!file_p.ptr)
961
return 0;
962
1097
1098
norigin = get_origin(sb, parent, p->one->path);
1099
hashcpy(norigin->blob_sha1, p->one->sha1);
1066
- fill_origin_blob(norigin, &file_p);
1100
+ fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
1101
if (!file_p.ptr)
1102
continue;
1103
2017
blame_date_mode = parse_date_format(value);
2018
return 0;
2019
}
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
+
2030
return git_default_config(var, value, cb);
2031
}
2032
2034
* Prepare a dummy commit that represents the work tree (or staged) item.
2035
* Note that annotating work tree item never works in the reverse.
2036
*/
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)
2040
{
2041
struct commit *commit;
2042
struct origin *origin;
2064
if (!contents_from || strcmp("-", contents_from)) {
2065
struct stat st;
2066
const char *read_from;
2067
+ unsigned long buf_len;
2068
2069
if (contents_from) {
2070
if (stat(contents_from, &st) < 0)
2077
read_from = path;
2078
}
2079
mode = canon_mode(st.st_mode);
2080
+
2081
switch (st.st_mode & S_IFMT) {
2082
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)
2087
die_errno("cannot open or read '%s'", read_from);
2088
break;
2089
case S_IFLNK:
2299
git_config(git_blame_config, NULL);
2300
init_revisions(&revs, NULL);
2301
revs.date_mode = blame_date_mode;
2302
+ DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV);
2303
2304
save_commit_buffer = 0;
2305
dashdash_pos = 0;
2436
* or "--contents".
2437
*/
2438
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);
2441
add_pending_object(&revs, &(sb.final->object), ":");
2442
}
2443
else if (contents_from)
2464
if (fill_blob_sha1(o))
2465
die("no such path %s in %s", path, final_commit_name);
2466
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
+
2475
if (!sb.final_buf)
2476
die("Cannot read blob %s for path %s",
2477
sha1_to_hex(o->blob_sha1),