apply.c | 269 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 268 insertions(+), 1 deletions(-) diff --git a/apply.c b/apply.c index 1742ab2..d606f4c 100644 --- a/apply.c +++ b/apply.c @@ -27,11 +27,12 @@ static int numstat = 0; static int summary = 0; static int check = 0; static int apply = 1; +static int annotate = 0; static int no_add = 0; static int show_index_info = 0; static int line_termination = '\n'; static const char apply_usage[] = -"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] ..."; +"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--annotate] [--no-add] [--index-info] [--allow-binary-replacement] [-z] ..."; /* * For "diff-stat" like behaviour, we keep track of the biggest change @@ -1439,6 +1440,264 @@ static void numstat_patch_list(struct pa } } + +struct blame_line { + const char *source; + int length; +}; + +struct blame { + struct blame *next; + struct patch *patch; + struct blame_line *lines; + unsigned long size; +}; + +struct revline { + struct blame *blame; + unsigned int ignore:1; +}; + +static struct revline *revlines; +static unsigned long revsize; + +static struct revline *get_revline(unsigned long lineno) +{ + if (revsize < lineno) { + printf("resizing %ld %ld\n", lineno, revsize); + revlines = xrealloc(revlines, sizeof(struct revline) * (lineno + 1)); + memset(&revlines[revsize + 1], 0, (lineno - revsize) * sizeof(struct revline)); + + if (revsize == 0) + memset(revlines, 0, sizeof(struct revline)); + revsize = lineno; + } + + return &revlines[lineno]; +} + +static void add_revlines(unsigned long lineno, unsigned long lines) +{ + unsigned long minsize = revsize > lineno + lines ? revsize : lineno + lines; + unsigned long revend = revsize; + struct revline *newend = get_revline(minsize); + struct revline *end = get_revline(revend); + struct revline *from = get_revline(lineno); + struct revline *to = get_revline(lineno + lines); + + (void) newend; + + { + unsigned long i; + + printf("start %d %p\n", revlines->ignore, revlines->blame); + for (i = 1; i <= revsize; i++) { + printf("%4ld : %d %p %d\n", i, revlines[i].ignore, revlines[i].blame, revlines[i].blame ? revlines[i].blame->size : 0); + } + } + if (end > from) + memmove(from, to, (end - from) * sizeof(*from)); + else + printf("%d", end - from); + + printf("moving %p:%ld to %p:%ld %d", from, lineno, to, lineno + lines, (end - from)); + + for (; from < to; from++) { + from->blame = NULL; + from->ignore = 1; + } +} + +static void del_revlines(unsigned long lineno, unsigned long lines) +{ + unsigned long minsize = revsize > lineno + lines ? revsize : lineno + lines; + unsigned long revend = revsize; + struct revline *newend = get_revline(minsize); + struct revline *from = get_revline(lineno + lines); + struct revline *to = get_revline(lineno); + struct revline *end = get_revline(revend); + struct revline *pos; + struct blame *list = NULL; + struct blame *listend = NULL; + + (void) newend; + +/* printf("del %ld %ld\n", lineno, lines);*/ + + for (pos = to; pos < from; pos++) { + if (pos->blame) { + if (!list) { + list = pos->blame; + listend = pos->blame; + } else { + listend->next = pos->blame; + } + + while (listend->next) + listend = listend->next; + + pos->blame = NULL; + } + } + + if (end > from) + memmove(from, to, (end - from) * sizeof(*from)); + + if (!list) return; + + if (from == revlines) + die("Oops, line number is zero"); + + from--; + + if (from->blame) { + struct blame *blame = from->blame; + + while (blame->next) + blame = blame->next; + + blame->next = list; + + } else { + from->blame = list; + } +} + +static struct blame *add_blame(struct patch *patch, struct blame *base, + unsigned long lineno, const char *src, int len) +{ + struct revline *revline = get_revline(lineno); + struct blame *blame; + + if (revline->ignore) + return NULL; + +/* printf("blame %p %p\n", base, revline->blame);*/ + if (!base || revline->blame) { + blame = xcalloc(1, sizeof(*blame)); + blame->patch = patch; + + if (revline->blame) { + struct blame *list = revline->blame; + + while (list->next) + list = list->next; + + list->next = blame; + + } else { + revline->blame = blame; +/* printf("blame %p %p\n", base, revline->blame);*/ + } + + } else { + blame = base; + } + +/* printf("blame [%.*s]\n", len, src);*/ + + blame->lines = xrealloc(blame->lines, sizeof(*blame->lines) * (blame->size + 1)); + blame->lines[blame->size].source = src; + blame->lines[blame->size].length = len; + blame->size++; + + return blame; +} + +static void annotate_fragment(struct patch *patch, struct fragment *frag) +{ + unsigned long adds, dels; + const char *src = frag->patch; + int len = frag->size; + unsigned long newpos = frag->newpos; + unsigned long oldpos = frag->oldpos; + struct blame *blame = NULL; + + if (oldpos == 0) oldpos = 1; + + adds = dels = 0; + + do { + int linelength = linelen(src, len); + int abslength = linelength - 1 - (src[linelength - 1] == '\n'); + + switch (*src) { + case '@': + printf("begin adds dels : %.*s\n", abslength, src + 1); + break; + + case '+': + printf("add %4ld : %.*s\n", newpos + adds, abslength, src + 1); + blame = add_blame(patch, blame, oldpos + adds, src + 1, abslength); + del_revlines(oldpos + adds, 1); + adds++; + break; + + case '-': + blame = NULL; + printf("dels %4ld : %.*s\n", oldpos + dels, abslength, src + 1); + dels++; + break; + + default: + blame = NULL; + if (dels) + add_revlines(oldpos, dels); + oldpos += dels; + newpos += adds; + + adds = dels = 0; + printf(" %4ld %4ld : %.*s\n", newpos + adds, oldpos + dels, abslength, src + 1); + oldpos++; + newpos++; + break; + } + + len -= linelength; + src += linelength; + + } while (len > 0); + + if (dels) + add_revlines(oldpos, dels); + + printf("%d fragment size\n", frag->size); +} + +static void annotate_patch(struct patch *patch) +{ + struct fragment *frag; + + for (frag = patch->fragments; frag ; frag = frag->next) { + if (frag->size && frag->patch) + annotate_fragment(patch, frag); + } + + { + unsigned long i; + + printf("start %d %p\n", revlines->ignore, revlines->blame); + for (i = 1; i <= revsize; i++) { + printf("%4ld : %d %p %d\n", i, revlines[i].ignore, revlines[i].blame, revlines[i].blame ? revlines[i].blame->size : 0); + } + } + +} + +static void annotate_patch_list(struct patch *patch) +{ + int revs, adds, dels; + + for (revs = adds = dels = 0 ; patch ; patch = patch->next) { + annotate_patch(patch); + adds += patch->lines_added; + dels += patch->lines_deleted; + revs++; + } + + printf(" %d revisions, %d annotated lines, %d insertions(+), %d deletions(-)\n", revs, adds - dels, adds, dels); +} + static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name) { if (mode) @@ -1775,6 +2034,9 @@ static int apply_patch(int fd) if (show_index_info) show_index_list(list); + if (annotate) + annotate_patch_list(list); + if (diffstat) stat_patch_list(list); @@ -1845,6 +2107,11 @@ int main(int argc, char **argv) apply = 1; continue; } + if (!strcmp(arg, "--annotate")) { + apply = 0; + annotate = 1; + continue; + } if (!strcmp(arg, "--index-info")) { apply = 0; show_index_info = 1;