Skip to content

Commit 9a4a100

Browse files
author
Linus Torvalds
committed
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..
1 parent 4dfdbe1 commit 9a4a100

File tree

1 file changed

+68
-19
lines changed

1 file changed

+68
-19
lines changed

apply.c

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,42 @@ static int is_dev_null(const char *str)
8585
return !memcmp("/dev/null", str, 9) && isspace(str[9]);
8686
}
8787

88-
static char * find_name(const char *line, char *def, int p_value)
88+
#define TERM_EXIST 1
89+
#define TERM_SPACE 2
90+
#define TERM_TAB 4
91+
92+
static int name_terminate(const char *name, int namelen, int c, int terminate)
93+
{
94+
if (c == ' ' && !(terminate & TERM_SPACE))
95+
return 0;
96+
if (c == '\t' && !(terminate & TERM_TAB))
97+
return 0;
98+
99+
/*
100+
* Do we want an existing name? Return false and
101+
* continue if it's not there.
102+
*/
103+
if (terminate & TERM_EXIST)
104+
return cache_name_pos(name, namelen) >= 0;
105+
106+
return 1;
107+
}
108+
109+
static char * find_name(const char *line, char *def, int p_value, int terminate)
89110
{
90111
int len;
91112
const char *start = line;
92113
char *name;
93114

94115
for (;;) {
95116
char c = *line;
96-
if (isspace(c))
97-
break;
117+
118+
if (isspace(c)) {
119+
if (c == '\n')
120+
break;
121+
if (name_terminate(start, line-start, c, terminate))
122+
break;
123+
}
98124
line++;
99125
if (c == '/' && !--p_value)
100126
start = line;
@@ -128,6 +154,10 @@ static char * find_name(const char *line, char *def, int p_value)
128154
* Get the name etc info from the --/+++ lines of a traditional patch header
129155
*
130156
* NOTE! This hardcodes "-p1" behaviour in filename detection.
157+
*
158+
* FIXME! The end-of-filename heuristics are kind of screwy. For existing
159+
* files, we can happily check the index for a match, but for creating a
160+
* new file we should try to match whatever "patch" does. I have no idea.
131161
*/
132162
static int parse_traditional_patch(const char *first, const char *second)
133163
{
@@ -138,18 +168,19 @@ static int parse_traditional_patch(const char *first, const char *second)
138168
second += 4; // skip "+++ "
139169
if (is_dev_null(first)) {
140170
is_new = 1;
141-
name = find_name(second, def_name, p_value);
171+
name = find_name(second, def_name, p_value, TERM_SPACE | TERM_TAB);
172+
new_name = name;
142173
} else if (is_dev_null(second)) {
143174
is_delete = 1;
144-
name = find_name(first, def_name, p_value);
175+
name = find_name(first, def_name, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB);
176+
old_name = name;
145177
} else {
146-
name = find_name(first, def_name, p_value);
147-
name = find_name(second, name, p_value);
178+
name = find_name(first, def_name, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB);
179+
name = find_name(second, name, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB);
180+
old_name = new_name = name;
148181
}
149182
if (!name)
150183
die("unable to find filename in patch at line %d", linenr);
151-
old_name = name;
152-
new_name = name;
153184
}
154185

155186
static int gitdiff_hdrend(const char *line)
@@ -159,15 +190,15 @@ static int gitdiff_hdrend(const char *line)
159190

160191
static int gitdiff_oldname(const char *line)
161192
{
162-
if (!old_name)
163-
old_name = find_name(line, NULL, 1);
193+
if (!old_name && !is_new)
194+
old_name = find_name(line, NULL, 1, 0);
164195
return 0;
165196
}
166197

167198
static int gitdiff_newname(const char *line)
168199
{
169-
if (!new_name)
170-
new_name = find_name(line, NULL, 1);
200+
if (!new_name && !is_delete)
201+
new_name = find_name(line, NULL, 1, 0);
171202
return 0;
172203
}
173204

@@ -198,28 +229,28 @@ static int gitdiff_newfile(const char *line)
198229
static int gitdiff_copysrc(const char *line)
199230
{
200231
is_copy = 1;
201-
old_name = find_name(line, NULL, 0);
232+
old_name = find_name(line, NULL, 0, 0);
202233
return 0;
203234
}
204235

205236
static int gitdiff_copydst(const char *line)
206237
{
207238
is_copy = 1;
208-
new_name = find_name(line, NULL, 0);
239+
new_name = find_name(line, NULL, 0, 0);
209240
return 0;
210241
}
211242

212243
static int gitdiff_renamesrc(const char *line)
213244
{
214245
is_rename = 1;
215-
old_name = find_name(line, NULL, 0);
246+
old_name = find_name(line, NULL, 0, 0);
216247
return 0;
217248
}
218249

219250
static int gitdiff_renamedst(const char *line)
220251
{
221252
is_rename = 1;
222-
new_name = find_name(line, NULL, 0);
253+
new_name = find_name(line, NULL, 0, 0);
223254
return 0;
224255
}
225256

@@ -228,6 +259,15 @@ static int gitdiff_similarity(const char *line)
228259
return 0;
229260
}
230261

262+
/*
263+
* This is normal for a diff that doesn't change anything: we'll fall through
264+
* into the next diff. Tell the parser to break out.
265+
*/
266+
static int gitdiff_unrecognized(const char *line)
267+
{
268+
return -1;
269+
}
270+
231271
/* Verify that we recognize the lines following a git header */
232272
static int parse_git_header(char *line, int len, unsigned int size)
233273
{
@@ -257,6 +297,7 @@ static int parse_git_header(char *line, int len, unsigned int size)
257297
{ "rename from ", gitdiff_renamesrc },
258298
{ "rename to ", gitdiff_renamedst },
259299
{ "similarity index ", gitdiff_similarity },
300+
{ "", gitdiff_unrecognized },
260301
};
261302
int i;
262303

@@ -270,6 +311,7 @@ static int parse_git_header(char *line, int len, unsigned int size)
270311
continue;
271312
if (p->fn(line + oplen) < 0)
272313
return offset;
314+
break;
273315
}
274316
}
275317

@@ -478,8 +520,15 @@ printf("Rename: %d\n", is_rename);
478520
printf("Copy: %d\n", is_copy);
479521
printf("New: %d\n", is_new);
480522
printf("Delete: %d\n", is_delete);
481-
printf("Mode: %o->%o\n", old_mode, new_mode);
482-
printf("Name: '%s'->'%s'\n", old_name, new_name);
523+
printf("Mode: %o:%o\n", old_mode, new_mode);
524+
printf("Name: '%s':'%s'\n", old_name, new_name);
525+
526+
if (old_name && cache_name_pos(old_name, strlen(old_name)) < 0)
527+
die("file %s does not exist", old_name);
528+
if (new_name && (is_new | is_rename | is_copy)) {
529+
if (cache_name_pos(new_name, strlen(new_name)) >= 0)
530+
die("file %s already exists", new_name);
531+
}
483532

484533
patch = header + hdrsize;
485534
patchsize = apply_single_patch(patch, size - offset - hdrsize);

0 commit comments

Comments
 (0)