2 * wiggle - apply rejected patches
4 * Copyright (C) 2003-2013 Neil Brown <neilb@suse.de>
5 * Copyright (C) 2014-2020 Neil Brown <neil@brown.name>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program.
22 * Email: <neil@brown.name>
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 wiggle_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 wiggle_Cmd, strip, pl[i].file);
85 memmove(pl[i].file, p, strlen(p)+1);
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... */
138 memmove(file, file+1, strlen(file));
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);
162 memset(&pl[n], 0, sizeof(pl[n]));
166 pl[n].last = pl[n].next = pl[n].prev = pl[n].parent = -1;
167 pl[n].conflicts = 100;
173 static struct plist *add_dir(struct plist *pl, int *np, char *file, char *curr)
175 /* any parent of file that is not a parent of curr
176 * needs to be added to pl
178 int d = common_depth(file, curr);
181 char *c = strchr(file, '/');
196 if (curr > buf && curr[-1] != '/')
198 while (*file && *file != '/')
204 pl = patch_add_file(pl, np, strdup(buf),
210 struct plist *wiggle_sort_patches(struct plist *pl, int *np)
212 /* sort the patches, add directory names, and re-sort */
218 qsort(pl, *np, sizeof(struct plist), pl_cmp);
221 for (i = 0; i < n; i++)
222 pl = add_dir(pl, np, pl[i].file, curr);
224 qsort(pl, *np, sizeof(struct plist), pl_cmp);
226 /* array is now stable, so set up parent pointers */
231 for (i = 0; i < n; i++) {
232 int d = common_depth(prev, pl[i].file);
236 pl[i].parent = parents[d-1];
237 pl[pl[i].parent].last = i;
239 pl[i].prev = prevnode[d];
241 pl[pl[i].prev].next = i;
250 struct plist *wiggle_parse_patch(FILE *f, FILE *of, int *np)
252 /* read a multi-file patch from 'f' and record relevant
253 * details in a plist.
254 * if 'of' >= 0, fd might not be seekable so we write
255 * to 'of' and use lseek on 'of' to determine position
257 struct plist *plist = NULL;
261 /* first, find the start of a patch: "\n+++ "
262 * grab the file name and scan to the end of a line
264 char *target = "\n+++ ";
265 char *target2 = "\n--- ";
271 while (*pos && (c = fgetc(f)) != EOF) {
282 /* now read a file name */
284 while ((c = fgetc(f)) != EOF
285 && c != '\t' && c != '\n' && c != ' ' &&
296 while (c != '\n' && (c = fgetc(f)) != EOF)
300 start = ftell(of ? of : f);
305 /* now skip to end - "\n--- " */
308 while (*pos && (c = fgetc(f)) != EOF) {
316 end = ftell(of ? of : f);
318 end -= (pos - target2) - 1;
319 plist = patch_add_file(plist, np,
320 strdup(name), start, end);
325 void wiggle_plist_free(struct plist *pl, int num)
328 for (i = 0; i < num ; i++)