diff options
-rw-r--r-- | blame.c | 160 |
1 files changed, 67 insertions, 93 deletions
@@ -16,6 +16,7 @@ #include "diff.h" #include "diffcore.h" #include "revision.h" +#include "xdiff-interface.h" #define DEBUG 0 @@ -57,116 +58,89 @@ static int num_get_patch = 0; static int num_commits = 0; static int patch_time = 0; -#define TEMPFILE_PATH_LEN 60 -static struct patch *get_patch(struct commit *commit, struct commit *other) -{ +struct blame_diff_state { + struct xdiff_emit_state xm; struct patch *ret; - struct util_info *info_c = (struct util_info *)commit->object.util; - struct util_info *info_o = (struct util_info *)other->object.util; - char tmp_path1[TEMPFILE_PATH_LEN], tmp_path2[TEMPFILE_PATH_LEN]; - char diff_cmd[TEMPFILE_PATH_LEN*2 + 20]; - struct timeval tv_start, tv_end; - int fd; - FILE *fin; - char buf[1024]; - - ret = xmalloc(sizeof(struct patch)); - ret->chunks = NULL; - ret->num = 0; - - get_blob(commit); - get_blob(other); +}; - gettimeofday(&tv_start, NULL); +static void process_u0_diff(void *state_, char *line, unsigned long len) +{ + struct blame_diff_state *state = state_; + struct chunk *chunk; - fd = git_mkstemp(tmp_path1, TEMPFILE_PATH_LEN, "git-blame-XXXXXX"); - if (fd < 0) - die("unable to create temp-file: %s", strerror(errno)); + if (len < 4 || line[0] != '@' || line[1] != '@') + return; - if (xwrite(fd, info_c->buf, info_c->size) != info_c->size) - die("write failed: %s", strerror(errno)); - close(fd); + if (DEBUG) + printf("chunk line: %.*s", (int)len, line); + state->ret->num++; + state->ret->chunks = xrealloc(state->ret->chunks, + sizeof(struct chunk) * state->ret->num); + chunk = &state->ret->chunks[state->ret->num - 1]; + + assert(!strncmp(line, "@@ -", 4)); + + if (parse_hunk_header(line, len, + &chunk->off1, &chunk->len1, + &chunk->off2, &chunk->len2)) { + state->ret->num--; + return; + } - fd = git_mkstemp(tmp_path2, TEMPFILE_PATH_LEN, "git-blame-XXXXXX"); - if (fd < 0) - die("unable to create temp-file: %s", strerror(errno)); + if (chunk->len1 == 0) + chunk->off1++; + if (chunk->len2 == 0) + chunk->off2++; - if (xwrite(fd, info_o->buf, info_o->size) != info_o->size) - die("write failed: %s", strerror(errno)); - close(fd); + if (chunk->off1 > 0) + chunk->off1--; + if (chunk->off2 > 0) + chunk->off2--; - sprintf(diff_cmd, "diff -U 0 %s %s", tmp_path1, tmp_path2); - fin = popen(diff_cmd, "r"); - if (!fin) - die("popen failed: %s", strerror(errno)); + assert(chunk->off1 >= 0); + assert(chunk->off2 >= 0); +} - while (fgets(buf, sizeof(buf), fin)) { - struct chunk *chunk; - char *start, *sp; +static struct patch *get_patch(struct commit *commit, struct commit *other) +{ + struct blame_diff_state state; + xpparam_t xpp; + xdemitconf_t xecfg; + mmfile_t file_c, file_o; + xdemitcb_t ecb; + struct util_info *info_c = (struct util_info *)commit->object.util; + struct util_info *info_o = (struct util_info *)other->object.util; + struct timeval tv_start, tv_end; - if (buf[0] != '@' || buf[1] != '@') - continue; + get_blob(commit); + file_c.ptr = info_c->buf; + file_c.size = info_c->size; - if (DEBUG) - printf("chunk line: %s", buf); - ret->num++; - ret->chunks = xrealloc(ret->chunks, - sizeof(struct chunk) * ret->num); - chunk = &ret->chunks[ret->num - 1]; - - assert(!strncmp(buf, "@@ -", 4)); - - start = buf + 4; - sp = index(start, ' '); - *sp = '\0'; - if (index(start, ',')) { - int ret = - sscanf(start, "%d,%d", &chunk->off1, &chunk->len1); - assert(ret == 2); - } else { - int ret = sscanf(start, "%d", &chunk->off1); - assert(ret == 1); - chunk->len1 = 1; - } - *sp = ' '; - - start = sp + 1; - sp = index(start, ' '); - *sp = '\0'; - if (index(start, ',')) { - int ret = - sscanf(start, "%d,%d", &chunk->off2, &chunk->len2); - assert(ret == 2); - } else { - int ret = sscanf(start, "%d", &chunk->off2); - assert(ret == 1); - chunk->len2 = 1; - } - *sp = ' '; + get_blob(other); + file_o.ptr = info_o->buf; + file_o.size = info_o->size; - if (chunk->len1 == 0) - chunk->off1++; - if (chunk->len2 == 0) - chunk->off2++; + gettimeofday(&tv_start, NULL); - if (chunk->off1 > 0) - chunk->off1--; - if (chunk->off2 > 0) - chunk->off2--; + xpp.flags = XDF_NEED_MINIMAL; + xecfg.ctxlen = 0; + xecfg.flags = 0; + ecb.outf = xdiff_outf; + ecb.priv = &state; + memset(&state, 0, sizeof(state)); + state.xm.consume = process_u0_diff; + state.ret = xmalloc(sizeof(struct patch)); + state.ret->chunks = NULL; + state.ret->num = 0; - assert(chunk->off1 >= 0); - assert(chunk->off2 >= 0); - } - pclose(fin); - unlink(tmp_path1); - unlink(tmp_path2); + xdl_diff(&file_c, &file_o, &xpp, &xecfg, &ecb); gettimeofday(&tv_end, NULL); patch_time += 1000000 * (tv_end.tv_sec - tv_start.tv_sec) + tv_end.tv_usec - tv_start.tv_usec; num_get_patch++; - return ret; + return state.ret; } static void free_patch(struct patch *p) @@ -674,7 +648,7 @@ static void get_commit_info(struct commit* commit, struct commit_info* ret) static char author_buf[1024]; tmp = strstr(commit->buffer, "\nauthor ") + 8; - len = index(tmp, '\n') - tmp; + len = strchr(tmp, '\n') - tmp; ret->author = author_buf; memcpy(ret->author, tmp, len); @@ -875,7 +849,7 @@ int main(int argc, const char **argv) if(blame_contents[blame_len-1] != '\n') putc('\n', stdout); } else { - char* next_buf = index(buf, '\n') + 1; + char* next_buf = strchr(buf, '\n') + 1; fwrite(buf, next_buf - buf, 1, stdout); buf = next_buf; } |