summaryrefslogtreecommitdiff
path: root/apply.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-23 19:13:55 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-23 19:13:55 -0700
commit9a4a100eb46a769d1c5fa80c2daeb0b48a592d8d (patch)
tree80ad38d5af34cc52a359ef982520e8aec4e33867 /apply.c
parent4dfdbe10dc8ca02fff2d5f0ce181b45d39394d56 (diff)
downloadgit-9a4a100eb46a769d1c5fa80c2daeb0b48a592d8d.tar.gz
git-apply: start using the index file information.
Right now we only use it to figure out what the filename might be when that is ambiguous, but we'll get there..
Diffstat (limited to 'apply.c')
-rw-r--r--apply.c87
1 files changed, 68 insertions, 19 deletions
diff --git a/apply.c b/apply.c
index f3b686541c..9dba588f02 100644
--- a/apply.c
+++ b/apply.c
@@ -85,7 +85,28 @@ static int is_dev_null(const char *str)
return !memcmp("/dev/null", str, 9) && isspace(str[9]);
}
-static char * find_name(const char *line, char *def, int p_value)
+#define TERM_EXIST 1
+#define TERM_SPACE 2
+#define TERM_TAB 4
+
+static int name_terminate(const char *name, int namelen, int c, int terminate)
+{
+ if (c == ' ' && !(terminate & TERM_SPACE))
+ return 0;
+ if (c == '\t' && !(terminate & TERM_TAB))
+ return 0;
+
+ /*
+ * Do we want an existing name? Return false and
+ * continue if it's not there.
+ */
+ if (terminate & TERM_EXIST)
+ return cache_name_pos(name, namelen) >= 0;
+
+ return 1;
+}
+
+static char * find_name(const char *line, char *def, int p_value, int terminate)
{
int len;
const char *start = line;
@@ -93,8 +114,13 @@ static char * find_name(const char *line, char *def, int p_value)
for (;;) {
char c = *line;
- if (isspace(c))
- break;
+
+ if (isspace(c)) {
+ if (c == '\n')
+ break;
+ if (name_terminate(start, line-start, c, terminate))
+ break;
+ }
line++;
if (c == '/' && !--p_value)
start = line;
@@ -128,6 +154,10 @@ static char * find_name(const char *line, char *def, int p_value)
* Get the name etc info from the --/+++ lines of a traditional patch header
*
* NOTE! This hardcodes "-p1" behaviour in filename detection.
+ *
+ * FIXME! The end-of-filename heuristics are kind of screwy. For existing
+ * files, we can happily check the index for a match, but for creating a
+ * new file we should try to match whatever "patch" does. I have no idea.
*/
static int parse_traditional_patch(const char *first, const char *second)
{
@@ -138,18 +168,19 @@ static int parse_traditional_patch(const char *first, const char *second)
second += 4; // skip "+++ "
if (is_dev_null(first)) {
is_new = 1;
- name = find_name(second, def_name, p_value);
+ name = find_name(second, def_name, p_value, TERM_SPACE | TERM_TAB);
+ new_name = name;
} else if (is_dev_null(second)) {
is_delete = 1;
- name = find_name(first, def_name, p_value);
+ name = find_name(first, def_name, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB);
+ old_name = name;
} else {
- name = find_name(first, def_name, p_value);
- name = find_name(second, name, p_value);
+ name = find_name(first, def_name, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB);
+ name = find_name(second, name, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB);
+ old_name = new_name = name;
}
if (!name)
die("unable to find filename in patch at line %d", linenr);
- old_name = name;
- new_name = name;
}
static int gitdiff_hdrend(const char *line)
@@ -159,15 +190,15 @@ static int gitdiff_hdrend(const char *line)
static int gitdiff_oldname(const char *line)
{
- if (!old_name)
- old_name = find_name(line, NULL, 1);
+ if (!old_name && !is_new)
+ old_name = find_name(line, NULL, 1, 0);
return 0;
}
static int gitdiff_newname(const char *line)
{
- if (!new_name)
- new_name = find_name(line, NULL, 1);
+ if (!new_name && !is_delete)
+ new_name = find_name(line, NULL, 1, 0);
return 0;
}
@@ -198,28 +229,28 @@ static int gitdiff_newfile(const char *line)
static int gitdiff_copysrc(const char *line)
{
is_copy = 1;
- old_name = find_name(line, NULL, 0);
+ old_name = find_name(line, NULL, 0, 0);
return 0;
}
static int gitdiff_copydst(const char *line)
{
is_copy = 1;
- new_name = find_name(line, NULL, 0);
+ new_name = find_name(line, NULL, 0, 0);
return 0;
}
static int gitdiff_renamesrc(const char *line)
{
is_rename = 1;
- old_name = find_name(line, NULL, 0);
+ old_name = find_name(line, NULL, 0, 0);
return 0;
}
static int gitdiff_renamedst(const char *line)
{
is_rename = 1;
- new_name = find_name(line, NULL, 0);
+ new_name = find_name(line, NULL, 0, 0);
return 0;
}
@@ -228,6 +259,15 @@ static int gitdiff_similarity(const char *line)
return 0;
}
+/*
+ * This is normal for a diff that doesn't change anything: we'll fall through
+ * into the next diff. Tell the parser to break out.
+ */
+static int gitdiff_unrecognized(const char *line)
+{
+ return -1;
+}
+
/* Verify that we recognize the lines following a git header */
static int parse_git_header(char *line, int len, unsigned int size)
{
@@ -257,6 +297,7 @@ static int parse_git_header(char *line, int len, unsigned int size)
{ "rename from ", gitdiff_renamesrc },
{ "rename to ", gitdiff_renamedst },
{ "similarity index ", gitdiff_similarity },
+ { "", gitdiff_unrecognized },
};
int i;
@@ -270,6 +311,7 @@ static int parse_git_header(char *line, int len, unsigned int size)
continue;
if (p->fn(line + oplen) < 0)
return offset;
+ break;
}
}
@@ -478,8 +520,15 @@ printf("Rename: %d\n", is_rename);
printf("Copy: %d\n", is_copy);
printf("New: %d\n", is_new);
printf("Delete: %d\n", is_delete);
-printf("Mode: %o->%o\n", old_mode, new_mode);
-printf("Name: '%s'->'%s'\n", old_name, new_name);
+printf("Mode: %o:%o\n", old_mode, new_mode);
+printf("Name: '%s':'%s'\n", old_name, new_name);
+
+ if (old_name && cache_name_pos(old_name, strlen(old_name)) < 0)
+ die("file %s does not exist", old_name);
+ if (new_name && (is_new | is_rename | is_copy)) {
+ if (cache_name_pos(new_name, strlen(new_name)) >= 0)
+ die("file %s already exists", new_name);
+ }
patch = header + hdrsize;
patchsize = apply_single_patch(patch, size - offset - hdrsize);