2 * wiggle - apply rejected patches
4 * Copyright (C) 2003-2012 Neil Brown <neilb@suse.de>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * Email: <neilb@suse.de>
26 * Parse a patch file to find the names of the different
27 * files to patch and record which parts of the patch
28 * file applies to which target file.
35 /* determine how much we need to stripe of the front of
36 * paths to find them from current directory. This is
37 * used to guess correct '-p' value.
39 static int get_strip(char *file
)
44 while (file
&& *file
) {
45 fd
= open(file
, O_RDONLY
);
51 file
= strchr(file
, '/');
60 int set_prefix(struct plist
*pl
, int n
, int strip
)
63 for (i
= 0; i
< 4 && i
< n
&& strip
< 0; i
++)
64 strip
= get_strip(pl
[i
].file
);
67 fprintf(stderr
, "%s: Cannot find files to patch: please specify --strip\n",
71 for (i
= 0; i
< n
; i
++) {
74 for (j
= 0; j
< strip
; j
++) {
77 while (p
&& *p
== '/')
81 fprintf(stderr
, "%s: cannot strip %d segments from %s\n",
82 Cmd
, strip
, pl
[i
].file
);
90 static int pl_cmp(const void *av
, const void *bv
)
92 const struct plist
*a
= av
;
93 const struct plist
*b
= bv
;
94 return strcmp(a
->file
, b
->file
);
97 static int common_depth(char *a
, char *b
)
99 /* find number of path segments that these two have
116 if (al
== 0 || al
!= bl
|| strncmp(a
, b
, al
) != 0)
129 static struct plist
*patch_add_file(struct plist
*pl
, int *np
, char *file
,
130 unsigned int start
, unsigned int end
)
132 /* size of pl is 0, 16, n^2 */
137 /* leading '/' are bad... */
144 else if ((n
&(n
-1)) == 0)
147 asize
= n
+1; /* not accurate, but not too large */
149 /* need to extend array */
155 npl
= realloc(pl
, asize
* sizeof(struct plist
));
157 fprintf(stderr
, "realloc failed - skipping %s\n", file
);
165 pl
[n
].last
= pl
[n
].next
= pl
[n
].prev
= pl
[n
].parent
= -1;
166 pl
[n
].chunks
= pl
[n
].wiggles
= 0; pl
[n
].conflicts
= 100;
174 static struct plist
*add_dir(struct plist
*pl
, int *np
, char *file
, char *curr
)
176 /* any parent of file that is not a parent of curr
177 * needs to be added to pl
179 int d
= common_depth(file
, curr
);
182 char *c
= strchr(file
, '/');
197 if (curr
> buf
&& curr
[-1] != '/')
199 while (*file
&& *file
!= '/')
205 pl
= patch_add_file(pl
, np
, strdup(buf
),
211 struct plist
*sort_patches(struct plist
*pl
, int *np
)
213 /* sort the patches, add directory names, and re-sort */
219 qsort(pl
, *np
, sizeof(struct plist
), pl_cmp
);
222 for (i
= 0; i
< n
; i
++)
223 pl
= add_dir(pl
, np
, pl
[i
].file
, curr
);
225 qsort(pl
, *np
, sizeof(struct plist
), pl_cmp
);
227 /* array is now stable, so set up parent pointers */
232 for (i
= 0; i
< n
; i
++) {
233 int d
= common_depth(prev
, pl
[i
].file
);
237 pl
[i
].parent
= parents
[d
-1];
238 pl
[pl
[i
].parent
].last
= i
;
240 pl
[i
].prev
= prevnode
[d
];
242 pl
[pl
[i
].prev
].next
= i
;
251 struct plist
*parse_patch(FILE *f
, FILE *of
, int *np
)
253 /* read a multi-file patch from 'f' and record relevant
254 * details in a plist.
255 * if 'of' >= 0, fd might not be seekable so we write
256 * to 'of' and use lseek on 'of' to determine position
258 struct plist
*plist
= NULL
;
262 /* first, find the start of a patch: "\n+++ "
263 * grab the file name and scan to the end of a line
265 char *target
= "\n+++ ";
266 char *target2
= "\n--- ";
272 while (*pos
&& (c
= fgetc(f
)) != EOF
) {
283 /* now read a file name */
285 while ((c
= fgetc(f
)) != EOF
286 && c
!= '\t' && c
!= '\n' && c
!= ' ' &&
297 while (c
!= '\n' && (c
= fgetc(f
)) != EOF
)
301 start
= ftell(of
?: f
);
306 /* now skip to end - "\n--- " */
309 while (*pos
&& (c
= fgetc(f
)) != EOF
) {
317 end
= ftell(of
?: f
);
319 end
-= (pos
- target2
) - 1;
320 plist
= patch_add_file(plist
, np
,
321 strdup(name
), start
, end
);