2 * wiggle - apply rejected patches
4 * Copyright (C) 2003-2013 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.
21 * Email: <neilb@suse.de>
25 * Parse a patch file to find the names of the different
26 * files to patch and record which parts of the patch
27 * file applies to which target file.
34 /* determine how much we need to stripe of the front of
35 * paths to find them from current directory. This is
36 * used to guess correct '-p' value.
38 static int get_strip(char *file
)
43 while (file
&& *file
) {
44 fd
= open(file
, O_RDONLY
);
50 file
= strchr(file
, '/');
59 int set_prefix(struct plist
*pl
, int n
, int strip
)
62 for (i
= 0; i
< 4 && i
< n
&& strip
< 0; i
++)
63 strip
= get_strip(pl
[i
].file
);
66 fprintf(stderr
, "%s: Cannot find files to patch: please specify --strip\n",
70 for (i
= 0; i
< n
; i
++) {
73 for (j
= 0; j
< strip
; j
++) {
76 while (p
&& *p
== '/')
80 fprintf(stderr
, "%s: cannot strip %d segments from %s\n",
81 Cmd
, strip
, pl
[i
].file
);
84 memmove(pl
[i
].file
, p
, strlen(p
)+1);
89 static int pl_cmp(const void *av
, const void *bv
)
91 const struct plist
*a
= av
;
92 const struct plist
*b
= bv
;
93 return strcmp(a
->file
, b
->file
);
96 static int common_depth(char *a
, char *b
)
98 /* find number of path segments that these two have
115 if (al
== 0 || al
!= bl
|| strncmp(a
, b
, al
) != 0)
128 static struct plist
*patch_add_file(struct plist
*pl
, int *np
, char *file
,
129 unsigned int start
, unsigned int end
)
131 /* size of pl is 0, 16, n^2 */
136 /* leading '/' are bad... */
137 memmove(file
, file
+1, strlen(file
));
143 else if ((n
&(n
-1)) == 0)
146 asize
= n
+1; /* not accurate, but not too large */
148 /* need to extend array */
154 npl
= realloc(pl
, asize
* sizeof(struct plist
));
156 fprintf(stderr
, "realloc failed - skipping %s\n", file
);
161 memset(&pl
[n
], 0, sizeof(pl
[n
]));
165 pl
[n
].last
= pl
[n
].next
= pl
[n
].prev
= pl
[n
].parent
= -1;
166 pl
[n
].conflicts
= 100;
172 static struct plist
*add_dir(struct plist
*pl
, int *np
, char *file
, char *curr
)
174 /* any parent of file that is not a parent of curr
175 * needs to be added to pl
177 int d
= common_depth(file
, curr
);
180 char *c
= strchr(file
, '/');
195 if (curr
> buf
&& curr
[-1] != '/')
197 while (*file
&& *file
!= '/')
203 pl
= patch_add_file(pl
, np
, strdup(buf
),
209 struct plist
*sort_patches(struct plist
*pl
, int *np
)
211 /* sort the patches, add directory names, and re-sort */
217 qsort(pl
, *np
, sizeof(struct plist
), pl_cmp
);
220 for (i
= 0; i
< n
; i
++)
221 pl
= add_dir(pl
, np
, pl
[i
].file
, curr
);
223 qsort(pl
, *np
, sizeof(struct plist
), pl_cmp
);
225 /* array is now stable, so set up parent pointers */
230 for (i
= 0; i
< n
; i
++) {
231 int d
= common_depth(prev
, pl
[i
].file
);
235 pl
[i
].parent
= parents
[d
-1];
236 pl
[pl
[i
].parent
].last
= i
;
238 pl
[i
].prev
= prevnode
[d
];
240 pl
[pl
[i
].prev
].next
= i
;
249 struct plist
*parse_patch(FILE *f
, FILE *of
, int *np
)
251 /* read a multi-file patch from 'f' and record relevant
252 * details in a plist.
253 * if 'of' >= 0, fd might not be seekable so we write
254 * to 'of' and use lseek on 'of' to determine position
256 struct plist
*plist
= NULL
;
260 /* first, find the start of a patch: "\n+++ "
261 * grab the file name and scan to the end of a line
263 char *target
= "\n+++ ";
264 char *target2
= "\n--- ";
270 while (*pos
&& (c
= fgetc(f
)) != EOF
) {
281 /* now read a file name */
283 while ((c
= fgetc(f
)) != EOF
284 && c
!= '\t' && c
!= '\n' && c
!= ' ' &&
295 while (c
!= '\n' && (c
= fgetc(f
)) != EOF
)
299 start
= ftell(of
?: f
);
304 /* now skip to end - "\n--- " */
307 while (*pos
&& (c
= fgetc(f
)) != EOF
) {
315 end
= ftell(of
?: f
);
317 end
-= (pos
- target2
) - 1;
318 plist
= patch_add_file(plist
, np
,
319 strdup(name
), start
, end
);
324 void plist_free(struct plist
*pl
, int num
)
327 for (i
= 0; i
< num
; i
++)