From 9a4a100eb46a769d1c5fa80c2daeb0b48a592d8d Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 23 May 2005 19:13:55 -0700 Subject: [PATCH] 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.. --- apply.c | 87 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 19 deletions(-) diff --git a/apply.c b/apply.c index f3b686541..9dba588f0 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); -- 2.30.2