git/diff-helper.c
Junio C Hamano ddafa7e933 [PATCH] diff-helper: Fix R/C score parsing under -z flag.
The score number that follow R/C status were parsed but the
parse pointer was not updated, causing the entire line to become
unrecognized.  This patch fixes this problem.

There was a test missing to catch this breakage, which this
commit adds as t4009-diff-rename-4.sh.  The diff-raw tests used
in related t4005-diff-rename-2.sh (the same test without -z) and
t4007-rename-3.sh were stricter than necessarily, despite that
the comment for the tests said otherwise.  This patch also
corrects them.

The documentation is updated to say that the status can
optionally be followed by a number called "score"; it does not
have to stay similarity index forever and there is no reason to
limit it only to C and R.

Signed-off-by: Junio C Hamano <junkio@cox.net>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-30 10:35:49 -07:00

148 lines
3.1 KiB
C

/*
* Copyright (C) 2005 Junio C Hamano
*/
#include "cache.h"
#include "strbuf.h"
#include "diff.h"
static const char *pickaxe = NULL;
static int pickaxe_opts = 0;
static int line_termination = '\n';
static int inter_name_termination = '\t';
static const char *diff_helper_usage =
"git-diff-helper [-z] [-S<string>] paths...";
int main(int ac, const char **av) {
struct strbuf sb;
const char *garbage_flush_format;
strbuf_init(&sb);
while (1 < ac && av[1][0] == '-') {
if (av[1][1] == 'z')
line_termination = inter_name_termination = 0;
else if (av[1][1] == 'S') {
pickaxe = av[1] + 2;
}
else if (!strcmp(av[1], "--pickaxe-all"))
pickaxe_opts = DIFF_PICKAXE_ALL;
else
usage(diff_helper_usage);
ac--; av++;
}
garbage_flush_format = (line_termination == 0) ? "%s" : "%s\n";
/* the remaining parameters are paths patterns */
diff_setup(0);
while (1) {
unsigned old_mode, new_mode;
unsigned char old_sha1[20], new_sha1[20];
char old_path[PATH_MAX];
int status, score, two_paths;
char new_path[PATH_MAX];
int ch;
char *cp, *ep;
read_line(&sb, stdin, line_termination);
if (sb.eof)
break;
switch (sb.buf[0]) {
case ':':
/* parse the first part up to the status */
cp = sb.buf + 1;
old_mode = new_mode = 0;
while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
old_mode = (old_mode << 3) | (ch - '0');
cp++;
}
if (*cp++ != ' ')
break;
while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
new_mode = (new_mode << 3) | (ch - '0');
cp++;
}
if (*cp++ != ' ')
break;
if (get_sha1_hex(cp, old_sha1))
break;
cp += 40;
if (*cp++ != ' ')
break;
if (get_sha1_hex(cp, new_sha1))
break;
cp += 40;
if (*cp++ != ' ')
break;
status = *cp++;
if (!strchr("MCRNDU", status))
break;
two_paths = score = 0;
if (status == 'R' || status == 'C')
two_paths = 1;
/* pick up score if exists */
if (sscanf(cp, "%d", &score) != 1)
score = 0;
cp = strchr(cp,
inter_name_termination);
if (!cp)
break;
if (*cp++ != inter_name_termination)
break;
/* first pathname */
if (!line_termination) {
read_line(&sb, stdin, line_termination);
if (sb.eof)
break;
strcpy(old_path, sb.buf);
}
else if (!two_paths)
strcpy(old_path, cp);
else {
ep = strchr(cp, inter_name_termination);
if (!ep)
break;
strncpy(old_path, cp, ep-cp);
old_path[ep-cp] = 0;
cp = ep + 1;
}
/* second pathname */
if (!two_paths)
strcpy(new_path, old_path);
else {
if (!line_termination) {
read_line(&sb, stdin,
line_termination);
if (sb.eof)
break;
strcpy(new_path, sb.buf);
}
else
strcpy(new_path, cp);
}
diff_helper_input(old_mode, new_mode,
old_sha1, new_sha1,
old_path, status, score,
new_path);
continue;
}
if (1 < ac)
diffcore_pathspec(av + 1);
if (pickaxe)
diffcore_pickaxe(pickaxe, pickaxe_opts);
diff_flush(DIFF_FORMAT_PATCH, 0);
printf(garbage_flush_format, sb.buf);
}
if (1 < ac)
diffcore_pathspec(av + 1);
if (pickaxe)
diffcore_pickaxe(pickaxe, pickaxe_opts);
diff_flush(DIFF_FORMAT_PATCH, 0);
return 0;
}