@@ -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 */
132162static 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
155186static int gitdiff_hdrend (const char * line )
@@ -159,15 +190,15 @@ static int gitdiff_hdrend(const char *line)
159190
160191static 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
167198static 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)
198229static 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
205236static 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
212243static 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
219250static 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 */
232272static 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);
478520printf ("Copy: %d\n" , is_copy );
479521printf ("New: %d\n" , is_new );
480522printf ("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