Merge lp:~jamesodhunt/ubuntu/trusty/patch/bug-1306412 into lp:ubuntu/trusty/patch
- Trusty (14.04)
- bug-1306412
- Merge into trusty
Proposed by
James Hunt
Status: | Rejected | ||||
---|---|---|---|---|---|
Rejected by: | Brian Murray | ||||
Proposed branch: | lp:~jamesodhunt/ubuntu/trusty/patch/bug-1306412 | ||||
Merge into: | lp:ubuntu/trusty/patch | ||||
Diff against target: |
2055 lines (+2009/-1) 6 files modified
.pc/applied-patches (+1/-0) .pc/fix-non-numeric-arg-crash.diff/src/patch.c (+1979/-0) debian/changelog (+7/-0) debian/patches/fix-non-numeric-arg-crash.diff (+19/-0) debian/patches/series (+1/-0) src/patch.c (+2/-1) |
||||
To merge this branch: | bzr merge lp:~jamesodhunt/ubuntu/trusty/patch/bug-1306412 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu branches | Pending | ||
Review via email: mp+217937@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
James Hunt (jamesodhunt) wrote : | # |
Revision history for this message
Brian Murray (brian-murray) wrote : | # |
I've already uploaded a fix for this to Trusty.
Unmerged revisions
- 14. By James Hunt
-
debian/
patches/ fix-non- numeric- arg-crash. diff: Fix crash when option
expecting a numeric given non-numeric (LP: #1306412).
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.pc/applied-patches' | |||
2 | --- .pc/applied-patches 2013-11-04 12:36:11 +0000 | |||
3 | +++ .pc/applied-patches 2014-05-01 16:07:46 +0000 | |||
4 | @@ -2,3 +2,4 @@ | |||
5 | 2 | 558485-backupmode | 2 | 558485-backupmode |
6 | 3 | m-merge | 3 | m-merge |
7 | 4 | add_manpage_time.patch | 4 | add_manpage_time.patch |
8 | 5 | fix-non-numeric-arg-crash.diff | ||
9 | 5 | 6 | ||
10 | === added directory '.pc/fix-non-numeric-arg-crash.diff' | |||
11 | === added file '.pc/fix-non-numeric-arg-crash.diff/.timestamp' | |||
12 | === added directory '.pc/fix-non-numeric-arg-crash.diff/src' | |||
13 | === added file '.pc/fix-non-numeric-arg-crash.diff/src/patch.c' | |||
14 | --- .pc/fix-non-numeric-arg-crash.diff/src/patch.c 1970-01-01 00:00:00 +0000 | |||
15 | +++ .pc/fix-non-numeric-arg-crash.diff/src/patch.c 2014-05-01 16:07:46 +0000 | |||
16 | @@ -0,0 +1,1979 @@ | |||
17 | 1 | /* patch - a program to apply diffs to original files */ | ||
18 | 2 | |||
19 | 3 | /* Copyright (C) 1984, 1985, 1986, 1987, 1988 Larry Wall | ||
20 | 4 | |||
21 | 5 | Copyright (C) 1989-1993, 1997-1999, 2002-2003, 2006, 2009-2012 Free Software | ||
22 | 6 | Foundation, Inc. | ||
23 | 7 | |||
24 | 8 | This program is free software: you can redistribute it and/or modify | ||
25 | 9 | it under the terms of the GNU General Public License as published by | ||
26 | 10 | the Free Software Foundation, either version 3 of the License, or | ||
27 | 11 | (at your option) any later version. | ||
28 | 12 | |||
29 | 13 | This program is distributed in the hope that it will be useful, | ||
30 | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
31 | 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
32 | 16 | GNU General Public License for more details. | ||
33 | 17 | |||
34 | 18 | You should have received a copy of the GNU General Public License | ||
35 | 19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
36 | 20 | |||
37 | 21 | #define XTERN | ||
38 | 22 | #include <common.h> | ||
39 | 23 | #undef XTERN | ||
40 | 24 | #define XTERN extern | ||
41 | 25 | #include <argmatch.h> | ||
42 | 26 | #include <exitfail.h> | ||
43 | 27 | #include <getopt.h> | ||
44 | 28 | #include <inp.h> | ||
45 | 29 | #include <pch.h> | ||
46 | 30 | #include <quotearg.h> | ||
47 | 31 | #include <util.h> | ||
48 | 32 | #include <version.h> | ||
49 | 33 | #include <xalloc.h> | ||
50 | 34 | #include <gl_linked_list.h> | ||
51 | 35 | #include <gl_xlist.h> | ||
52 | 36 | |||
53 | 37 | /* procedures */ | ||
54 | 38 | |||
55 | 39 | static FILE *create_output_file (char const *, int); | ||
56 | 40 | static lin locate_hunk (lin); | ||
57 | 41 | static bool check_line_endings (lin); | ||
58 | 42 | static bool apply_hunk (struct outstate *, lin); | ||
59 | 43 | static bool patch_match (lin, lin, lin, lin); | ||
60 | 44 | static bool spew_output (struct outstate *, struct stat *); | ||
61 | 45 | static int numeric_string (char const *, bool, char const *); | ||
62 | 46 | static void cleanup (void); | ||
63 | 47 | static void get_some_switches (void); | ||
64 | 48 | static void init_output (struct outstate *); | ||
65 | 49 | static FILE *open_outfile (char const *); | ||
66 | 50 | static void init_reject (char const *); | ||
67 | 51 | static void reinitialize_almost_everything (void); | ||
68 | 52 | static void remove_if_needed (char const *, bool *); | ||
69 | 53 | static void usage (FILE *, int) __attribute__((noreturn)); | ||
70 | 54 | |||
71 | 55 | static void abort_hunk (char const *, bool, bool); | ||
72 | 56 | static void abort_hunk_context (bool, bool); | ||
73 | 57 | static void abort_hunk_unified (bool, bool); | ||
74 | 58 | |||
75 | 59 | static void output_file (char const *, bool *, const struct stat *, char const *, | ||
76 | 60 | const struct stat *, mode_t, bool); | ||
77 | 61 | |||
78 | 62 | static void init_files_to_delete (void); | ||
79 | 63 | static void init_files_to_output (void); | ||
80 | 64 | static void delete_files (void); | ||
81 | 65 | static void output_files (struct stat const *); | ||
82 | 66 | |||
83 | 67 | #ifdef ENABLE_MERGE | ||
84 | 68 | static bool merge; | ||
85 | 69 | #else | ||
86 | 70 | # define merge false | ||
87 | 71 | #endif | ||
88 | 72 | |||
89 | 73 | static enum diff reject_format = NO_DIFF; /* automatic */ | ||
90 | 74 | static bool make_backups; | ||
91 | 75 | static bool backup_if_mismatch; | ||
92 | 76 | static char const *version_control; | ||
93 | 77 | static char const *version_control_context; | ||
94 | 78 | static bool remove_empty_files; | ||
95 | 79 | static bool explicit_inname; | ||
96 | 80 | static enum { RO_IGNORE, RO_WARN, RO_FAIL } read_only_behavior = RO_WARN; | ||
97 | 81 | |||
98 | 82 | /* true if -R was specified on command line. */ | ||
99 | 83 | static bool reverse_flag_specified; | ||
100 | 84 | |||
101 | 85 | static char const *do_defines; /* symbol to patch using ifdef, ifndef, etc. */ | ||
102 | 86 | static char const if_defined[] = "\n#ifdef %s\n"; | ||
103 | 87 | static char const not_defined[] = "\n#ifndef %s\n"; | ||
104 | 88 | static char const else_defined[] = "\n#else\n"; | ||
105 | 89 | static char const end_defined[] = "\n#endif\n"; | ||
106 | 90 | |||
107 | 91 | static int Argc; | ||
108 | 92 | static char **Argv; | ||
109 | 93 | |||
110 | 94 | static FILE *rejfp; /* reject file pointer */ | ||
111 | 95 | |||
112 | 96 | static char const *patchname; | ||
113 | 97 | static char *rejname; | ||
114 | 98 | static char const * TMPREJNAME; | ||
115 | 99 | static bool TMPREJNAME_needs_removal; | ||
116 | 100 | |||
117 | 101 | static lin maxfuzz = 2; | ||
118 | 102 | |||
119 | 103 | static char serrbuf[BUFSIZ]; | ||
120 | 104 | |||
121 | 105 | /* Apply a set of diffs as appropriate. */ | ||
122 | 106 | |||
123 | 107 | int | ||
124 | 108 | main (int argc, char **argv) | ||
125 | 109 | { | ||
126 | 110 | char const *val; | ||
127 | 111 | bool somefailed = false; | ||
128 | 112 | struct outstate outstate; | ||
129 | 113 | struct stat tmpoutst; | ||
130 | 114 | char numbuf[LINENUM_LENGTH_BOUND + 1]; | ||
131 | 115 | bool written_to_rejname = false; | ||
132 | 116 | bool apply_empty_patch = false; | ||
133 | 117 | mode_t file_type; | ||
134 | 118 | int outfd = -1; | ||
135 | 119 | bool have_git_diff = false; | ||
136 | 120 | |||
137 | 121 | exit_failure = 2; | ||
138 | 122 | set_program_name (argv[0]); | ||
139 | 123 | init_time (); | ||
140 | 124 | |||
141 | 125 | setbuf(stderr, serrbuf); | ||
142 | 126 | |||
143 | 127 | bufsize = 8 * 1024; | ||
144 | 128 | buf = xmalloc (bufsize); | ||
145 | 129 | |||
146 | 130 | strippath = -1; | ||
147 | 131 | |||
148 | 132 | val = getenv ("QUOTING_STYLE"); | ||
149 | 133 | { | ||
150 | 134 | int i = val ? argmatch (val, quoting_style_args, 0, 0) : -1; | ||
151 | 135 | set_quoting_style ((struct quoting_options *) 0, | ||
152 | 136 | i < 0 ? shell_quoting_style : (enum quoting_style) i); | ||
153 | 137 | } | ||
154 | 138 | |||
155 | 139 | posixly_correct = getenv ("POSIXLY_CORRECT") != 0; | ||
156 | 140 | backup_if_mismatch = ! posixly_correct; | ||
157 | 141 | patch_get = ((val = getenv ("PATCH_GET")) | ||
158 | 142 | ? numeric_string (val, true, "PATCH_GET value") | ||
159 | 143 | : 0); | ||
160 | 144 | |||
161 | 145 | val = getenv ("SIMPLE_BACKUP_SUFFIX"); | ||
162 | 146 | simple_backup_suffix = val && *val ? val : ".orig"; | ||
163 | 147 | |||
164 | 148 | if ((version_control = getenv ("PATCH_VERSION_CONTROL"))) | ||
165 | 149 | version_control_context = "$PATCH_VERSION_CONTROL"; | ||
166 | 150 | else if ((version_control = getenv ("VERSION_CONTROL"))) | ||
167 | 151 | version_control_context = "$VERSION_CONTROL"; | ||
168 | 152 | |||
169 | 153 | /* parse switches */ | ||
170 | 154 | Argc = argc; | ||
171 | 155 | Argv = argv; | ||
172 | 156 | get_some_switches(); | ||
173 | 157 | |||
174 | 158 | /* Make get_date() assume that context diff headers use UTC. */ | ||
175 | 159 | if (set_utc) | ||
176 | 160 | setenv ("TZ", "UTC", 1); | ||
177 | 161 | |||
178 | 162 | if (make_backups | backup_if_mismatch) | ||
179 | 163 | backup_type = get_version (version_control_context, version_control); | ||
180 | 164 | |||
181 | 165 | init_backup_hash_table (); | ||
182 | 166 | init_files_to_delete (); | ||
183 | 167 | init_files_to_output (); | ||
184 | 168 | |||
185 | 169 | init_output (&outstate); | ||
186 | 170 | if (outfile) | ||
187 | 171 | outstate.ofp = open_outfile (outfile); | ||
188 | 172 | |||
189 | 173 | /* Make sure we clean up in case of disaster. */ | ||
190 | 174 | set_signals (false); | ||
191 | 175 | |||
192 | 176 | if (inname && outfile) | ||
193 | 177 | { | ||
194 | 178 | /* When an input and an output filename is given and the patch is | ||
195 | 179 | empty, copy the input file to the output file. In this case, the | ||
196 | 180 | input file must be a regular file (i.e., symlinks cannot be copied | ||
197 | 181 | this way). */ | ||
198 | 182 | apply_empty_patch = true; | ||
199 | 183 | file_type = S_IFREG; | ||
200 | 184 | inerrno = -1; | ||
201 | 185 | } | ||
202 | 186 | for ( | ||
203 | 187 | open_patch_file (patchname); | ||
204 | 188 | there_is_another_patch (! (inname || posixly_correct), &file_type) | ||
205 | 189 | || apply_empty_patch; | ||
206 | 190 | reinitialize_almost_everything(), | ||
207 | 191 | apply_empty_patch = false | ||
208 | 192 | ) { /* for each patch in patch file */ | ||
209 | 193 | int hunk = 0; | ||
210 | 194 | int failed = 0; | ||
211 | 195 | bool mismatch = false; | ||
212 | 196 | char const *outname = NULL; | ||
213 | 197 | |||
214 | 198 | if (have_git_diff != pch_git_diff ()) | ||
215 | 199 | { | ||
216 | 200 | if (have_git_diff) | ||
217 | 201 | { | ||
218 | 202 | output_files (NULL); | ||
219 | 203 | inerrno = -1; | ||
220 | 204 | } | ||
221 | 205 | have_git_diff = ! have_git_diff; | ||
222 | 206 | } | ||
223 | 207 | |||
224 | 208 | if (TMPREJNAME_needs_removal) | ||
225 | 209 | { | ||
226 | 210 | if (rejfp) | ||
227 | 211 | { | ||
228 | 212 | fclose (rejfp); | ||
229 | 213 | rejfp = NULL; | ||
230 | 214 | } | ||
231 | 215 | remove_if_needed (TMPREJNAME, &TMPREJNAME_needs_removal); | ||
232 | 216 | } | ||
233 | 217 | if (TMPOUTNAME_needs_removal) | ||
234 | 218 | { | ||
235 | 219 | if (outfd != -1) | ||
236 | 220 | { | ||
237 | 221 | close (outfd); | ||
238 | 222 | outfd = -1; | ||
239 | 223 | } | ||
240 | 224 | remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal); | ||
241 | 225 | } | ||
242 | 226 | |||
243 | 227 | if (! skip_rest_of_patch && ! file_type) | ||
244 | 228 | { | ||
245 | 229 | say ("File %s: can't change file type from 0%o to 0%o.\n", | ||
246 | 230 | quotearg (inname), | ||
247 | 231 | pch_mode (reverse) & S_IFMT, | ||
248 | 232 | pch_mode (! reverse) & S_IFMT); | ||
249 | 233 | skip_rest_of_patch = true; | ||
250 | 234 | somefailed = true; | ||
251 | 235 | } | ||
252 | 236 | |||
253 | 237 | if (! skip_rest_of_patch) | ||
254 | 238 | { | ||
255 | 239 | if (outfile) | ||
256 | 240 | outname = outfile; | ||
257 | 241 | else if (pch_copy () || pch_rename ()) | ||
258 | 242 | outname = pch_name (! strcmp (inname, pch_name (OLD))); | ||
259 | 243 | else | ||
260 | 244 | outname = inname; | ||
261 | 245 | } | ||
262 | 246 | |||
263 | 247 | if (pch_git_diff () && ! skip_rest_of_patch) | ||
264 | 248 | { | ||
265 | 249 | struct stat outstat; | ||
266 | 250 | int outerrno = 0; | ||
267 | 251 | |||
268 | 252 | /* Try to recognize concatenated git diffs based on the SHA1 hashes | ||
269 | 253 | in the headers. Will not always succeed for patches that rename | ||
270 | 254 | or copy files. */ | ||
271 | 255 | |||
272 | 256 | if (! strcmp (inname, outname)) | ||
273 | 257 | { | ||
274 | 258 | if (inerrno == -1) | ||
275 | 259 | inerrno = stat_file (inname, &instat); | ||
276 | 260 | outstat = instat; | ||
277 | 261 | outerrno = inerrno; | ||
278 | 262 | } | ||
279 | 263 | else | ||
280 | 264 | outerrno = stat_file (outname, &outstat); | ||
281 | 265 | |||
282 | 266 | if (! outerrno) | ||
283 | 267 | { | ||
284 | 268 | if (has_queued_output (&outstat)) | ||
285 | 269 | { | ||
286 | 270 | output_files (&outstat); | ||
287 | 271 | outerrno = stat_file (outname, &outstat); | ||
288 | 272 | inerrno = -1; | ||
289 | 273 | } | ||
290 | 274 | if (! outerrno) | ||
291 | 275 | set_queued_output (&outstat, true); | ||
292 | 276 | } | ||
293 | 277 | } | ||
294 | 278 | |||
295 | 279 | if (! skip_rest_of_patch) | ||
296 | 280 | { | ||
297 | 281 | if (! get_input_file (inname, outname, file_type)) | ||
298 | 282 | { | ||
299 | 283 | skip_rest_of_patch = true; | ||
300 | 284 | somefailed = true; | ||
301 | 285 | } | ||
302 | 286 | } | ||
303 | 287 | |||
304 | 288 | if (read_only_behavior != RO_IGNORE | ||
305 | 289 | && ! inerrno && ! S_ISLNK (instat.st_mode) | ||
306 | 290 | && access (inname, W_OK) != 0) | ||
307 | 291 | { | ||
308 | 292 | say ("File %s is read-only; ", quotearg (inname)); | ||
309 | 293 | if (read_only_behavior == RO_WARN) | ||
310 | 294 | say ("trying to patch anyway\n"); | ||
311 | 295 | else | ||
312 | 296 | { | ||
313 | 297 | say ("refusing to patch\n"); | ||
314 | 298 | skip_rest_of_patch = true; | ||
315 | 299 | somefailed = true; | ||
316 | 300 | } | ||
317 | 301 | } | ||
318 | 302 | |||
319 | 303 | tmpoutst.st_size = -1; | ||
320 | 304 | outfd = make_tempfile (&TMPOUTNAME, 'o', outname, | ||
321 | 305 | O_WRONLY | binary_transput, | ||
322 | 306 | instat.st_mode & S_IRWXUGO); | ||
323 | 307 | TMPOUTNAME_needs_removal = true; | ||
324 | 308 | if (diff_type == ED_DIFF) { | ||
325 | 309 | outstate.zero_output = false; | ||
326 | 310 | somefailed |= skip_rest_of_patch; | ||
327 | 311 | do_ed_script (inname, TMPOUTNAME, &TMPOUTNAME_needs_removal, | ||
328 | 312 | outstate.ofp); | ||
329 | 313 | if (! dry_run && ! outfile && ! skip_rest_of_patch) | ||
330 | 314 | { | ||
331 | 315 | if (fstat (outfd, &tmpoutst) != 0) | ||
332 | 316 | pfatal ("%s", TMPOUTNAME); | ||
333 | 317 | outstate.zero_output = tmpoutst.st_size == 0; | ||
334 | 318 | } | ||
335 | 319 | close (outfd); | ||
336 | 320 | outfd = -1; | ||
337 | 321 | } else { | ||
338 | 322 | int got_hunk; | ||
339 | 323 | bool apply_anyway = merge; /* don't try to reverse when merging */ | ||
340 | 324 | |||
341 | 325 | if (! skip_rest_of_patch && diff_type == GIT_BINARY_DIFF) { | ||
342 | 326 | say ("File %s: git binary diffs are not supported.\n", | ||
343 | 327 | quotearg (outname)); | ||
344 | 328 | skip_rest_of_patch = true; | ||
345 | 329 | somefailed = true; | ||
346 | 330 | } | ||
347 | 331 | /* initialize the patched file */ | ||
348 | 332 | if (! skip_rest_of_patch && ! outfile) | ||
349 | 333 | { | ||
350 | 334 | init_output (&outstate); | ||
351 | 335 | outstate.ofp = fdopen(outfd, binary_transput ? "wb" : "w"); | ||
352 | 336 | if (! outstate.ofp) | ||
353 | 337 | pfatal ("%s", TMPOUTNAME); | ||
354 | 338 | } | ||
355 | 339 | |||
356 | 340 | /* find out where all the lines are */ | ||
357 | 341 | if (!skip_rest_of_patch) { | ||
358 | 342 | scan_input (inname, file_type); | ||
359 | 343 | |||
360 | 344 | if (verbosity != SILENT) | ||
361 | 345 | { | ||
362 | 346 | bool renamed = strcmp (inname, outname); | ||
363 | 347 | |||
364 | 348 | say ("%s %s %s%c", | ||
365 | 349 | dry_run ? "checking" : "patching", | ||
366 | 350 | S_ISLNK (file_type) ? "symbolic link" : "file", | ||
367 | 351 | quotearg (outname), renamed ? ' ' : '\n'); | ||
368 | 352 | if (renamed) | ||
369 | 353 | say ("(%s from %s)\n", | ||
370 | 354 | pch_copy () ? "copied" : | ||
371 | 355 | (pch_rename () ? "renamed" : "read"), | ||
372 | 356 | inname); | ||
373 | 357 | if (verbosity == VERBOSE) | ||
374 | 358 | say ("Using Plan %s...\n", using_plan_a ? "A" : "B"); | ||
375 | 359 | } | ||
376 | 360 | } | ||
377 | 361 | |||
378 | 362 | /* from here on, open no standard i/o files, because malloc */ | ||
379 | 363 | /* might misfire and we can't catch it easily */ | ||
380 | 364 | |||
381 | 365 | /* apply each hunk of patch */ | ||
382 | 366 | while (0 < (got_hunk = another_hunk (diff_type, reverse))) | ||
383 | 367 | { | ||
384 | 368 | lin where = 0; /* Pacify 'gcc -Wall'. */ | ||
385 | 369 | lin newwhere; | ||
386 | 370 | lin fuzz = 0; | ||
387 | 371 | lin mymaxfuzz; | ||
388 | 372 | |||
389 | 373 | if (merge) | ||
390 | 374 | { | ||
391 | 375 | /* When in merge mode, don't apply with fuzz. */ | ||
392 | 376 | mymaxfuzz = 0; | ||
393 | 377 | } | ||
394 | 378 | else | ||
395 | 379 | { | ||
396 | 380 | lin prefix_context = pch_prefix_context (); | ||
397 | 381 | lin suffix_context = pch_suffix_context (); | ||
398 | 382 | lin context = (prefix_context < suffix_context | ||
399 | 383 | ? suffix_context : prefix_context); | ||
400 | 384 | mymaxfuzz = (maxfuzz < context ? maxfuzz : context); | ||
401 | 385 | } | ||
402 | 386 | |||
403 | 387 | hunk++; | ||
404 | 388 | if (!skip_rest_of_patch) { | ||
405 | 389 | do { | ||
406 | 390 | where = locate_hunk(fuzz); | ||
407 | 391 | if (! where || fuzz || in_offset) | ||
408 | 392 | mismatch = true; | ||
409 | 393 | if (hunk == 1 && ! where && ! (force | apply_anyway) | ||
410 | 394 | && reverse == reverse_flag_specified) { | ||
411 | 395 | /* dwim for reversed patch? */ | ||
412 | 396 | if (!pch_swap()) { | ||
413 | 397 | say ( | ||
414 | 398 | "Not enough memory to try swapped hunk! Assuming unswapped.\n"); | ||
415 | 399 | continue; | ||
416 | 400 | } | ||
417 | 401 | /* Try again. */ | ||
418 | 402 | where = locate_hunk (fuzz); | ||
419 | 403 | if (where | ||
420 | 404 | && (ok_to_reverse | ||
421 | 405 | ("%s patch detected!", | ||
422 | 406 | (reverse | ||
423 | 407 | ? "Unreversed" | ||
424 | 408 | : "Reversed (or previously applied)")))) | ||
425 | 409 | reverse = ! reverse; | ||
426 | 410 | else | ||
427 | 411 | { | ||
428 | 412 | /* Put it back to normal. */ | ||
429 | 413 | if (! pch_swap ()) | ||
430 | 414 | fatal ("lost hunk on alloc error!"); | ||
431 | 415 | if (where) | ||
432 | 416 | { | ||
433 | 417 | apply_anyway = true; | ||
434 | 418 | fuzz--; /* Undo '++fuzz' below. */ | ||
435 | 419 | where = 0; | ||
436 | 420 | } | ||
437 | 421 | } | ||
438 | 422 | } | ||
439 | 423 | } while (!skip_rest_of_patch && !where | ||
440 | 424 | && ++fuzz <= mymaxfuzz); | ||
441 | 425 | |||
442 | 426 | if (skip_rest_of_patch) { /* just got decided */ | ||
443 | 427 | if (outstate.ofp && ! outfile) | ||
444 | 428 | { | ||
445 | 429 | fclose (outstate.ofp); | ||
446 | 430 | outstate.ofp = 0; | ||
447 | 431 | outfd = -1; | ||
448 | 432 | } | ||
449 | 433 | } | ||
450 | 434 | } | ||
451 | 435 | |||
452 | 436 | newwhere = (where ? where : pch_first()) + out_offset; | ||
453 | 437 | if (skip_rest_of_patch | ||
454 | 438 | || (merge && ! merge_hunk (hunk, &outstate, where, | ||
455 | 439 | &somefailed)) | ||
456 | 440 | || (! merge | ||
457 | 441 | && ((where == 1 && pch_says_nonexistent (reverse) == 2 | ||
458 | 442 | && instat.st_size) | ||
459 | 443 | || ! where | ||
460 | 444 | || ! apply_hunk (&outstate, where)))) | ||
461 | 445 | { | ||
462 | 446 | abort_hunk (outname, ! failed, reverse); | ||
463 | 447 | failed++; | ||
464 | 448 | if (verbosity == VERBOSE || | ||
465 | 449 | (! skip_rest_of_patch && verbosity != SILENT)) | ||
466 | 450 | say ("Hunk #%d %s at %s%s.\n", hunk, | ||
467 | 451 | skip_rest_of_patch ? "ignored" : "FAILED", | ||
468 | 452 | format_linenum (numbuf, newwhere), | ||
469 | 453 | ! skip_rest_of_patch && check_line_endings (newwhere) | ||
470 | 454 | ? " (different line endings)" : ""); | ||
471 | 455 | } | ||
472 | 456 | else if (! merge && | ||
473 | 457 | (verbosity == VERBOSE | ||
474 | 458 | || (verbosity != SILENT && (fuzz || in_offset)))) | ||
475 | 459 | { | ||
476 | 460 | say ("Hunk #%d succeeded at %s", hunk, | ||
477 | 461 | format_linenum (numbuf, newwhere)); | ||
478 | 462 | if (fuzz) | ||
479 | 463 | say (" with fuzz %s", format_linenum (numbuf, fuzz)); | ||
480 | 464 | if (in_offset) | ||
481 | 465 | say (" (offset %s line%s)", | ||
482 | 466 | format_linenum (numbuf, in_offset), | ||
483 | 467 | "s" + (in_offset == 1)); | ||
484 | 468 | say (".\n"); | ||
485 | 469 | } | ||
486 | 470 | } | ||
487 | 471 | |||
488 | 472 | if (!skip_rest_of_patch) | ||
489 | 473 | { | ||
490 | 474 | if (got_hunk < 0 && using_plan_a) | ||
491 | 475 | { | ||
492 | 476 | if (outfile) | ||
493 | 477 | fatal ("out of memory using Plan A"); | ||
494 | 478 | say ("\n\nRan out of memory using Plan A -- trying again...\n\n"); | ||
495 | 479 | if (outstate.ofp) | ||
496 | 480 | { | ||
497 | 481 | fclose (outstate.ofp); | ||
498 | 482 | outstate.ofp = 0; | ||
499 | 483 | } | ||
500 | 484 | continue; | ||
501 | 485 | } | ||
502 | 486 | |||
503 | 487 | /* Finish spewing out the new file. */ | ||
504 | 488 | if (! spew_output (&outstate, &tmpoutst)) | ||
505 | 489 | { | ||
506 | 490 | say ("Skipping patch.\n"); | ||
507 | 491 | skip_rest_of_patch = true; | ||
508 | 492 | } | ||
509 | 493 | } | ||
510 | 494 | } | ||
511 | 495 | |||
512 | 496 | /* and put the output where desired */ | ||
513 | 497 | ignore_signals (); | ||
514 | 498 | if (! skip_rest_of_patch && ! outfile) { | ||
515 | 499 | bool backup = make_backups | ||
516 | 500 | || (backup_if_mismatch && (mismatch | failed)); | ||
517 | 501 | if (outstate.zero_output | ||
518 | 502 | && (remove_empty_files | ||
519 | 503 | || (pch_says_nonexistent (! reverse) == 2 | ||
520 | 504 | && ! posixly_correct) | ||
521 | 505 | || S_ISLNK (file_type))) | ||
522 | 506 | { | ||
523 | 507 | if (! dry_run) | ||
524 | 508 | output_file (NULL, NULL, NULL, outname, | ||
525 | 509 | (inname == outname) ? &instat : NULL, | ||
526 | 510 | file_type | 0, backup); | ||
527 | 511 | } | ||
528 | 512 | else | ||
529 | 513 | { | ||
530 | 514 | if (! outstate.zero_output | ||
531 | 515 | && pch_says_nonexistent (! reverse) == 2 | ||
532 | 516 | && (remove_empty_files || ! posixly_correct) | ||
533 | 517 | && ! (merge && somefailed)) | ||
534 | 518 | { | ||
535 | 519 | mismatch = true; | ||
536 | 520 | somefailed = true; | ||
537 | 521 | if (verbosity != SILENT) | ||
538 | 522 | say ("File %s is not empty after patch; not deleting\n", | ||
539 | 523 | quotearg (outname)); | ||
540 | 524 | } | ||
541 | 525 | |||
542 | 526 | if (! dry_run) | ||
543 | 527 | { | ||
544 | 528 | mode_t old_mode = pch_mode (reverse); | ||
545 | 529 | mode_t new_mode = pch_mode (! reverse); | ||
546 | 530 | bool set_mode = new_mode && old_mode != new_mode; | ||
547 | 531 | |||
548 | 532 | /* Avoid replacing files when nothing has changed. */ | ||
549 | 533 | if (failed < hunk || diff_type == ED_DIFF || set_mode | ||
550 | 534 | || pch_copy () || pch_rename ()) | ||
551 | 535 | { | ||
552 | 536 | enum file_attributes attr = 0; | ||
553 | 537 | struct timespec new_time = pch_timestamp (! reverse); | ||
554 | 538 | mode_t mode = file_type | | ||
555 | 539 | ((new_mode ? new_mode : instat.st_mode) & S_IRWXUGO); | ||
556 | 540 | |||
557 | 541 | if ((set_time | set_utc) && new_time.tv_sec != -1) | ||
558 | 542 | { | ||
559 | 543 | struct timespec old_time = pch_timestamp (reverse); | ||
560 | 544 | |||
561 | 545 | if (! force && ! inerrno | ||
562 | 546 | && pch_says_nonexistent (reverse) != 2 | ||
563 | 547 | && old_time.tv_sec != -1 | ||
564 | 548 | && timespec_cmp (old_time, | ||
565 | 549 | get_stat_mtime (&instat))) | ||
566 | 550 | say ("Not setting time of file %s " | ||
567 | 551 | "(time mismatch)\n", | ||
568 | 552 | quotearg (outname)); | ||
569 | 553 | else if (! force && (mismatch | failed)) | ||
570 | 554 | say ("Not setting time of file %s " | ||
571 | 555 | "(contents mismatch)\n", | ||
572 | 556 | quotearg (outname)); | ||
573 | 557 | else | ||
574 | 558 | attr |= FA_TIMES; | ||
575 | 559 | } | ||
576 | 560 | |||
577 | 561 | if (inerrno) | ||
578 | 562 | set_file_attributes (TMPOUTNAME, attr, NULL, NULL, | ||
579 | 563 | mode, &new_time); | ||
580 | 564 | else | ||
581 | 565 | { | ||
582 | 566 | attr |= FA_IDS | FA_MODE | FA_XATTRS; | ||
583 | 567 | set_file_attributes (TMPOUTNAME, attr, inname, &instat, | ||
584 | 568 | mode, &new_time); | ||
585 | 569 | } | ||
586 | 570 | |||
587 | 571 | output_file (TMPOUTNAME, &TMPOUTNAME_needs_removal, | ||
588 | 572 | &tmpoutst, outname, NULL, mode, backup); | ||
589 | 573 | |||
590 | 574 | if (pch_rename ()) | ||
591 | 575 | output_file (NULL, NULL, NULL, inname, &instat, | ||
592 | 576 | mode, backup); | ||
593 | 577 | } | ||
594 | 578 | else | ||
595 | 579 | output_file (outname, NULL, &tmpoutst, NULL, NULL, | ||
596 | 580 | file_type | 0, backup); | ||
597 | 581 | } | ||
598 | 582 | } | ||
599 | 583 | } | ||
600 | 584 | if (diff_type != ED_DIFF) { | ||
601 | 585 | struct stat rejst; | ||
602 | 586 | |||
603 | 587 | if (failed) { | ||
604 | 588 | if (fstat (fileno (rejfp), &rejst) != 0 || fclose (rejfp) != 0) | ||
605 | 589 | write_fatal (); | ||
606 | 590 | rejfp = NULL; | ||
607 | 591 | somefailed = true; | ||
608 | 592 | say ("%d out of %d hunk%s %s", failed, hunk, "s" + (hunk == 1), | ||
609 | 593 | skip_rest_of_patch ? "ignored" : "FAILED"); | ||
610 | 594 | if (outname && (! rejname || strcmp (rejname, "-") != 0)) { | ||
611 | 595 | char *rej = rejname; | ||
612 | 596 | if (!rejname) { | ||
613 | 597 | /* FIXME: This should really be done differently! */ | ||
614 | 598 | const char *s = simple_backup_suffix; | ||
615 | 599 | size_t len; | ||
616 | 600 | simple_backup_suffix = ".rej"; | ||
617 | 601 | rej = find_backup_file_name (outname, simple_backups); | ||
618 | 602 | len = strlen (rej); | ||
619 | 603 | if (rej[len - 1] == '~') | ||
620 | 604 | rej[len - 1] = '#'; | ||
621 | 605 | simple_backup_suffix = s; | ||
622 | 606 | } | ||
623 | 607 | if (! dry_run) | ||
624 | 608 | { | ||
625 | 609 | say (" -- saving rejects to file %s\n", quotearg (rej)); | ||
626 | 610 | if (rejname) | ||
627 | 611 | { | ||
628 | 612 | if (! written_to_rejname) | ||
629 | 613 | { | ||
630 | 614 | copy_file (TMPREJNAME, rejname, 0, 0, | ||
631 | 615 | S_IFREG | 0666, true); | ||
632 | 616 | written_to_rejname = true; | ||
633 | 617 | } | ||
634 | 618 | else | ||
635 | 619 | append_to_file (TMPREJNAME, rejname); | ||
636 | 620 | } | ||
637 | 621 | else | ||
638 | 622 | { | ||
639 | 623 | struct stat oldst; | ||
640 | 624 | int olderrno; | ||
641 | 625 | |||
642 | 626 | olderrno = stat_file (rej, &oldst); | ||
643 | 627 | if (olderrno && olderrno != ENOENT) | ||
644 | 628 | write_fatal (); | ||
645 | 629 | if (! olderrno && lookup_file_id (&oldst) == CREATED) | ||
646 | 630 | append_to_file (TMPREJNAME, rej); | ||
647 | 631 | else | ||
648 | 632 | move_file (TMPREJNAME, &TMPREJNAME_needs_removal, | ||
649 | 633 | &rejst, rej, S_IFREG | 0666, false); | ||
650 | 634 | } | ||
651 | 635 | } | ||
652 | 636 | else | ||
653 | 637 | say ("\n"); | ||
654 | 638 | if (!rejname) | ||
655 | 639 | free (rej); | ||
656 | 640 | } else | ||
657 | 641 | say ("\n"); | ||
658 | 642 | } | ||
659 | 643 | } | ||
660 | 644 | set_signals (true); | ||
661 | 645 | } | ||
662 | 646 | if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0)) | ||
663 | 647 | write_fatal (); | ||
664 | 648 | output_files (NULL); | ||
665 | 649 | delete_files (); | ||
666 | 650 | cleanup (); | ||
667 | 651 | if (somefailed) | ||
668 | 652 | exit (1); | ||
669 | 653 | return 0; | ||
670 | 654 | } | ||
671 | 655 | |||
672 | 656 | /* Prepare to find the next patch to do in the patch file. */ | ||
673 | 657 | |||
674 | 658 | static void | ||
675 | 659 | reinitialize_almost_everything (void) | ||
676 | 660 | { | ||
677 | 661 | re_patch(); | ||
678 | 662 | re_input(); | ||
679 | 663 | |||
680 | 664 | input_lines = 0; | ||
681 | 665 | last_frozen_line = 0; | ||
682 | 666 | |||
683 | 667 | if (inname && ! explicit_inname) { | ||
684 | 668 | free (inname); | ||
685 | 669 | inname = 0; | ||
686 | 670 | } | ||
687 | 671 | |||
688 | 672 | in_offset = 0; | ||
689 | 673 | out_offset = 0; | ||
690 | 674 | |||
691 | 675 | diff_type = NO_DIFF; | ||
692 | 676 | |||
693 | 677 | if (revision) { | ||
694 | 678 | free(revision); | ||
695 | 679 | revision = 0; | ||
696 | 680 | } | ||
697 | 681 | |||
698 | 682 | reverse = reverse_flag_specified; | ||
699 | 683 | skip_rest_of_patch = false; | ||
700 | 684 | } | ||
701 | 685 | |||
702 | 686 | static char const shortopts[] = "bB:cd:D:eEfF:g:i:l" | ||
703 | 687 | #if defined ENABLE_MERGE | ||
704 | 688 | "m" | ||
705 | 689 | #endif | ||
706 | 690 | "nNo:p:r:RstTuvV:x:Y:z:Z"; | ||
707 | 691 | |||
708 | 692 | static struct option const longopts[] = | ||
709 | 693 | { | ||
710 | 694 | {"backup", no_argument, NULL, 'b'}, | ||
711 | 695 | {"prefix", required_argument, NULL, 'B'}, | ||
712 | 696 | {"context", no_argument, NULL, 'c'}, | ||
713 | 697 | {"directory", required_argument, NULL, 'd'}, | ||
714 | 698 | {"ifdef", required_argument, NULL, 'D'}, | ||
715 | 699 | {"ed", no_argument, NULL, 'e'}, | ||
716 | 700 | {"remove-empty-files", no_argument, NULL, 'E'}, | ||
717 | 701 | {"force", no_argument, NULL, 'f'}, | ||
718 | 702 | {"fuzz", required_argument, NULL, 'F'}, | ||
719 | 703 | {"get", required_argument, NULL, 'g'}, | ||
720 | 704 | {"input", required_argument, NULL, 'i'}, | ||
721 | 705 | {"ignore-whitespace", no_argument, NULL, 'l'}, | ||
722 | 706 | #ifdef ENABLE_MERGE | ||
723 | 707 | {"merge", optional_argument, NULL, 'm'}, | ||
724 | 708 | #endif | ||
725 | 709 | {"normal", no_argument, NULL, 'n'}, | ||
726 | 710 | {"forward", no_argument, NULL, 'N'}, | ||
727 | 711 | {"output", required_argument, NULL, 'o'}, | ||
728 | 712 | {"strip", required_argument, NULL, 'p'}, | ||
729 | 713 | {"reject-file", required_argument, NULL, 'r'}, | ||
730 | 714 | {"reverse", no_argument, NULL, 'R'}, | ||
731 | 715 | {"quiet", no_argument, NULL, 's'}, | ||
732 | 716 | {"silent", no_argument, NULL, 's'}, | ||
733 | 717 | {"batch", no_argument, NULL, 't'}, | ||
734 | 718 | {"set-time", no_argument, NULL, 'T'}, | ||
735 | 719 | {"unified", no_argument, NULL, 'u'}, | ||
736 | 720 | {"version", no_argument, NULL, 'v'}, | ||
737 | 721 | {"version-control", required_argument, NULL, 'V'}, | ||
738 | 722 | {"debug", required_argument, NULL, 'x'}, | ||
739 | 723 | {"basename-prefix", required_argument, NULL, 'Y'}, | ||
740 | 724 | {"suffix", required_argument, NULL, 'z'}, | ||
741 | 725 | {"set-utc", no_argument, NULL, 'Z'}, | ||
742 | 726 | {"dry-run", no_argument, NULL, CHAR_MAX + 1}, | ||
743 | 727 | {"verbose", no_argument, NULL, CHAR_MAX + 2}, | ||
744 | 728 | {"binary", no_argument, NULL, CHAR_MAX + 3}, | ||
745 | 729 | {"help", no_argument, NULL, CHAR_MAX + 4}, | ||
746 | 730 | {"backup-if-mismatch", no_argument, NULL, CHAR_MAX + 5}, | ||
747 | 731 | {"no-backup-if-mismatch", no_argument, NULL, CHAR_MAX + 6}, | ||
748 | 732 | {"posix", no_argument, NULL, CHAR_MAX + 7}, | ||
749 | 733 | {"quoting-style", required_argument, NULL, CHAR_MAX + 8}, | ||
750 | 734 | {"reject-format", required_argument, NULL, CHAR_MAX + 9}, | ||
751 | 735 | {"read-only", required_argument, NULL, CHAR_MAX + 10}, | ||
752 | 736 | {"follow-symlinks", no_argument, NULL, CHAR_MAX + 11}, | ||
753 | 737 | {NULL, no_argument, NULL, 0} | ||
754 | 738 | }; | ||
755 | 739 | |||
756 | 740 | static char const *const option_help[] = | ||
757 | 741 | { | ||
758 | 742 | "Input options:", | ||
759 | 743 | "", | ||
760 | 744 | " -p NUM --strip=NUM Strip NUM leading components from file names.", | ||
761 | 745 | " -F LINES --fuzz LINES Set the fuzz factor to LINES for inexact matching.", | ||
762 | 746 | " -l --ignore-whitespace Ignore white space changes between patch and input.", | ||
763 | 747 | "", | ||
764 | 748 | " -c --context Interpret the patch as a context difference.", | ||
765 | 749 | " -e --ed Interpret the patch as an ed script.", | ||
766 | 750 | " -n --normal Interpret the patch as a normal difference.", | ||
767 | 751 | " -u --unified Interpret the patch as a unified difference.", | ||
768 | 752 | "", | ||
769 | 753 | " -N --forward Ignore patches that appear to be reversed or already applied.", | ||
770 | 754 | " -R --reverse Assume patches were created with old and new files swapped.", | ||
771 | 755 | "", | ||
772 | 756 | " -i PATCHFILE --input=PATCHFILE Read patch from PATCHFILE instead of stdin.", | ||
773 | 757 | "", | ||
774 | 758 | "Output options:", | ||
775 | 759 | "", | ||
776 | 760 | " -o FILE --output=FILE Output patched files to FILE.", | ||
777 | 761 | " -r FILE --reject-file=FILE Output rejects to FILE.", | ||
778 | 762 | "", | ||
779 | 763 | " -D NAME --ifdef=NAME Make merged if-then-else output using NAME.", | ||
780 | 764 | #ifdef ENABLE_MERGE | ||
781 | 765 | " -m --merge Merge using conflict markers instead of creating reject files.", | ||
782 | 766 | #endif | ||
783 | 767 | " -E --remove-empty-files Remove output files that are empty after patching.", | ||
784 | 768 | "", | ||
785 | 769 | " -Z --set-utc Set times of patched files, assuming diff uses UTC (GMT).", | ||
786 | 770 | " -T --set-time Likewise, assuming local time.", | ||
787 | 771 | "", | ||
788 | 772 | " --quoting-style=WORD output file names using quoting style WORD.", | ||
789 | 773 | " Valid WORDs are: literal, shell, shell-always, c, escape.", | ||
790 | 774 | " Default is taken from QUOTING_STYLE env variable, or 'shell' if unset.", | ||
791 | 775 | "", | ||
792 | 776 | "Backup and version control options:", | ||
793 | 777 | "", | ||
794 | 778 | " -b --backup Back up the original contents of each file.", | ||
795 | 779 | " --backup-if-mismatch Back up if the patch does not match exactly.", | ||
796 | 780 | " --no-backup-if-mismatch Back up mismatches only if otherwise requested.", | ||
797 | 781 | "", | ||
798 | 782 | " -V STYLE --version-control=STYLE Use STYLE version control.", | ||
799 | 783 | " STYLE is either 'simple', 'numbered', or 'existing'.", | ||
800 | 784 | " -B PREFIX --prefix=PREFIX Prepend PREFIX to backup file names.", | ||
801 | 785 | " -Y PREFIX --basename-prefix=PREFIX Prepend PREFIX to backup file basenames.", | ||
802 | 786 | " -z SUFFIX --suffix=SUFFIX Append SUFFIX to backup file names.", | ||
803 | 787 | "", | ||
804 | 788 | " -g NUM --get=NUM Get files from RCS etc. if positive; ask if negative.", | ||
805 | 789 | "", | ||
806 | 790 | "Miscellaneous options:", | ||
807 | 791 | "", | ||
808 | 792 | " -t --batch Ask no questions; skip bad-Prereq patches; assume reversed.", | ||
809 | 793 | " -f --force Like -t, but ignore bad-Prereq patches, and assume unreversed.", | ||
810 | 794 | " -s --quiet --silent Work silently unless an error occurs.", | ||
811 | 795 | " --verbose Output extra information about the work being done.", | ||
812 | 796 | " --dry-run Do not actually change any files; just print what would happen.", | ||
813 | 797 | " --posix Conform to the POSIX standard.", | ||
814 | 798 | "", | ||
815 | 799 | " -d DIR --directory=DIR Change the working directory to DIR first.", | ||
816 | 800 | " --reject-format=FORMAT Create 'context' or 'unified' rejects.", | ||
817 | 801 | " --binary Read and write data in binary mode.", | ||
818 | 802 | " --read-only=BEHAVIOR How to handle read-only input files: 'ignore' that they", | ||
819 | 803 | " are read-only, 'warn' (default), or 'fail'.", | ||
820 | 804 | "", | ||
821 | 805 | " -v --version Output version info.", | ||
822 | 806 | " --help Output this help.", | ||
823 | 807 | "", | ||
824 | 808 | "Report bugs to <" PACKAGE_BUGREPORT ">.", | ||
825 | 809 | 0 | ||
826 | 810 | }; | ||
827 | 811 | |||
828 | 812 | static void | ||
829 | 813 | usage (FILE *stream, int status) | ||
830 | 814 | { | ||
831 | 815 | char const * const *p; | ||
832 | 816 | |||
833 | 817 | if (status != 0) | ||
834 | 818 | { | ||
835 | 819 | fprintf (stream, "%s: Try '%s --help' for more information.\n", | ||
836 | 820 | program_name, Argv[0]); | ||
837 | 821 | } | ||
838 | 822 | else | ||
839 | 823 | { | ||
840 | 824 | fprintf (stream, "Usage: %s [OPTION]... [ORIGFILE [PATCHFILE]]\n\n", | ||
841 | 825 | Argv[0]); | ||
842 | 826 | for (p = option_help; *p; p++) | ||
843 | 827 | fprintf (stream, "%s\n", *p); | ||
844 | 828 | } | ||
845 | 829 | |||
846 | 830 | exit (status); | ||
847 | 831 | } | ||
848 | 832 | |||
849 | 833 | /* Process switches and filenames. */ | ||
850 | 834 | |||
851 | 835 | static void | ||
852 | 836 | get_some_switches (void) | ||
853 | 837 | { | ||
854 | 838 | int optc; | ||
855 | 839 | |||
856 | 840 | free (rejname); | ||
857 | 841 | rejname = 0; | ||
858 | 842 | if (optind == Argc) | ||
859 | 843 | return; | ||
860 | 844 | while ((optc = getopt_long (Argc, Argv, shortopts, longopts, (int *) 0)) | ||
861 | 845 | != -1) { | ||
862 | 846 | switch (optc) { | ||
863 | 847 | case 'b': | ||
864 | 848 | make_backups = true; | ||
865 | 849 | /* Special hack for backward compatibility with CVS 1.9. | ||
866 | 850 | If the last 4 args are '-b SUFFIX ORIGFILE PATCHFILE', | ||
867 | 851 | treat '-b' as if it were '-b -z'. */ | ||
868 | 852 | if (Argc - optind == 3 | ||
869 | 853 | && strcmp (Argv[optind - 1], "-b") == 0 | ||
870 | 854 | && ! (Argv[optind + 0][0] == '-' && Argv[optind + 0][1]) | ||
871 | 855 | && ! (Argv[optind + 1][0] == '-' && Argv[optind + 1][1]) | ||
872 | 856 | && ! (Argv[optind + 2][0] == '-' && Argv[optind + 2][1])) | ||
873 | 857 | { | ||
874 | 858 | optarg = Argv[optind++]; | ||
875 | 859 | if (verbosity != SILENT) | ||
876 | 860 | say ("warning: the '-b %s' option is obsolete; use '-b -z %s' instead\n", | ||
877 | 861 | optarg, optarg); | ||
878 | 862 | goto case_z; | ||
879 | 863 | } | ||
880 | 864 | break; | ||
881 | 865 | case 'B': | ||
882 | 866 | if (!*optarg) | ||
883 | 867 | fatal ("backup prefix is empty"); | ||
884 | 868 | origprae = savestr (optarg); | ||
885 | 869 | break; | ||
886 | 870 | case 'c': | ||
887 | 871 | diff_type = CONTEXT_DIFF; | ||
888 | 872 | break; | ||
889 | 873 | case 'd': | ||
890 | 874 | if (chdir(optarg) < 0) | ||
891 | 875 | pfatal ("Can't change to directory %s", quotearg (optarg)); | ||
892 | 876 | break; | ||
893 | 877 | case 'D': | ||
894 | 878 | do_defines = savestr (optarg); | ||
895 | 879 | break; | ||
896 | 880 | case 'e': | ||
897 | 881 | diff_type = ED_DIFF; | ||
898 | 882 | break; | ||
899 | 883 | case 'E': | ||
900 | 884 | remove_empty_files = true; | ||
901 | 885 | break; | ||
902 | 886 | case 'f': | ||
903 | 887 | force = true; | ||
904 | 888 | break; | ||
905 | 889 | case 'F': | ||
906 | 890 | maxfuzz = numeric_string (optarg, false, "fuzz factor"); | ||
907 | 891 | break; | ||
908 | 892 | case 'g': | ||
909 | 893 | patch_get = numeric_string (optarg, true, "get option value"); | ||
910 | 894 | break; | ||
911 | 895 | case 'i': | ||
912 | 896 | patchname = savestr (optarg); | ||
913 | 897 | break; | ||
914 | 898 | case 'l': | ||
915 | 899 | canonicalize = true; | ||
916 | 900 | break; | ||
917 | 901 | #ifdef ENABLE_MERGE | ||
918 | 902 | case 'm': | ||
919 | 903 | merge = true; | ||
920 | 904 | if (optarg) | ||
921 | 905 | { | ||
922 | 906 | if (! strcmp (optarg, "merge")) | ||
923 | 907 | conflict_style = MERGE_MERGE; | ||
924 | 908 | else if (! strcmp (optarg, "diff3")) | ||
925 | 909 | conflict_style = MERGE_DIFF3; | ||
926 | 910 | else | ||
927 | 911 | usage (stderr, 2); | ||
928 | 912 | } | ||
929 | 913 | else | ||
930 | 914 | conflict_style = MERGE_MERGE; | ||
931 | 915 | break; | ||
932 | 916 | #endif | ||
933 | 917 | case 'n': | ||
934 | 918 | diff_type = NORMAL_DIFF; | ||
935 | 919 | break; | ||
936 | 920 | case 'N': | ||
937 | 921 | noreverse = true; | ||
938 | 922 | break; | ||
939 | 923 | case 'o': | ||
940 | 924 | outfile = savestr (optarg); | ||
941 | 925 | break; | ||
942 | 926 | case 'p': | ||
943 | 927 | strippath = numeric_string (optarg, false, "strip count"); | ||
944 | 928 | break; | ||
945 | 929 | case 'r': | ||
946 | 930 | rejname = savestr (optarg); | ||
947 | 931 | break; | ||
948 | 932 | case 'R': | ||
949 | 933 | reverse = true; | ||
950 | 934 | reverse_flag_specified = true; | ||
951 | 935 | break; | ||
952 | 936 | case 's': | ||
953 | 937 | verbosity = SILENT; | ||
954 | 938 | break; | ||
955 | 939 | case 't': | ||
956 | 940 | batch = true; | ||
957 | 941 | break; | ||
958 | 942 | case 'T': | ||
959 | 943 | set_time = true; | ||
960 | 944 | break; | ||
961 | 945 | case 'u': | ||
962 | 946 | diff_type = UNI_DIFF; | ||
963 | 947 | break; | ||
964 | 948 | case 'v': | ||
965 | 949 | version(); | ||
966 | 950 | exit (0); | ||
967 | 951 | break; | ||
968 | 952 | case 'V': | ||
969 | 953 | version_control = optarg; | ||
970 | 954 | version_control_context = "--version-control or -V option"; | ||
971 | 955 | break; | ||
972 | 956 | #if DEBUGGING | ||
973 | 957 | case 'x': | ||
974 | 958 | debug = numeric_string (optarg, true, "debugging option"); | ||
975 | 959 | break; | ||
976 | 960 | #endif | ||
977 | 961 | case 'Y': | ||
978 | 962 | if (!*optarg) | ||
979 | 963 | fatal ("backup basename prefix is empty"); | ||
980 | 964 | origbase = savestr (optarg); | ||
981 | 965 | break; | ||
982 | 966 | case 'z': | ||
983 | 967 | case_z: | ||
984 | 968 | if (!*optarg) | ||
985 | 969 | fatal ("backup suffix is empty"); | ||
986 | 970 | origsuff = savestr (optarg); | ||
987 | 971 | break; | ||
988 | 972 | case 'Z': | ||
989 | 973 | set_utc = true; | ||
990 | 974 | break; | ||
991 | 975 | case CHAR_MAX + 1: | ||
992 | 976 | dry_run = true; | ||
993 | 977 | break; | ||
994 | 978 | case CHAR_MAX + 2: | ||
995 | 979 | verbosity = VERBOSE; | ||
996 | 980 | break; | ||
997 | 981 | case CHAR_MAX + 3: | ||
998 | 982 | no_strip_trailing_cr = true; | ||
999 | 983 | #if HAVE_SETMODE_DOS | ||
1000 | 984 | binary_transput = O_BINARY; | ||
1001 | 985 | #endif | ||
1002 | 986 | break; | ||
1003 | 987 | case CHAR_MAX + 4: | ||
1004 | 988 | usage (stdout, 0); | ||
1005 | 989 | case CHAR_MAX + 5: | ||
1006 | 990 | backup_if_mismatch = true; | ||
1007 | 991 | break; | ||
1008 | 992 | case CHAR_MAX + 6: | ||
1009 | 993 | backup_if_mismatch = false; | ||
1010 | 994 | break; | ||
1011 | 995 | case CHAR_MAX + 7: | ||
1012 | 996 | posixly_correct = true; | ||
1013 | 997 | break; | ||
1014 | 998 | case CHAR_MAX + 8: | ||
1015 | 999 | { | ||
1016 | 1000 | int i = argmatch (optarg, quoting_style_args, 0, 0); | ||
1017 | 1001 | if (i < 0) | ||
1018 | 1002 | { | ||
1019 | 1003 | invalid_arg ("quoting style", optarg, i); | ||
1020 | 1004 | usage (stderr, 2); | ||
1021 | 1005 | } | ||
1022 | 1006 | set_quoting_style ((struct quoting_options *) 0, | ||
1023 | 1007 | (enum quoting_style) i); | ||
1024 | 1008 | } | ||
1025 | 1009 | break; | ||
1026 | 1010 | case CHAR_MAX + 9: | ||
1027 | 1011 | if (strcmp (optarg, "context") == 0) | ||
1028 | 1012 | reject_format = NEW_CONTEXT_DIFF; | ||
1029 | 1013 | else if (strcmp (optarg, "unified") == 0) | ||
1030 | 1014 | reject_format = UNI_DIFF; | ||
1031 | 1015 | else | ||
1032 | 1016 | usage (stderr, 2); | ||
1033 | 1017 | break; | ||
1034 | 1018 | case CHAR_MAX + 10: | ||
1035 | 1019 | if (strcmp (optarg, "ignore") == 0) | ||
1036 | 1020 | read_only_behavior = RO_IGNORE; | ||
1037 | 1021 | else if (strcmp (optarg, "warn") == 0) | ||
1038 | 1022 | read_only_behavior = RO_WARN; | ||
1039 | 1023 | else if (strcmp (optarg, "fail") == 0) | ||
1040 | 1024 | read_only_behavior = RO_FAIL; | ||
1041 | 1025 | else | ||
1042 | 1026 | usage (stderr, 2); | ||
1043 | 1027 | break; | ||
1044 | 1028 | case CHAR_MAX + 11: | ||
1045 | 1029 | follow_symlinks = true; | ||
1046 | 1030 | break; | ||
1047 | 1031 | default: | ||
1048 | 1032 | usage (stderr, 2); | ||
1049 | 1033 | } | ||
1050 | 1034 | } | ||
1051 | 1035 | |||
1052 | 1036 | /* Process any filename args. */ | ||
1053 | 1037 | if (optind < Argc) | ||
1054 | 1038 | { | ||
1055 | 1039 | inname = savestr (Argv[optind++]); | ||
1056 | 1040 | explicit_inname = true; | ||
1057 | 1041 | invc = -1; | ||
1058 | 1042 | if (optind < Argc) | ||
1059 | 1043 | { | ||
1060 | 1044 | patchname = savestr (Argv[optind++]); | ||
1061 | 1045 | if (optind < Argc) | ||
1062 | 1046 | { | ||
1063 | 1047 | fprintf (stderr, "%s: %s: extra operand\n", | ||
1064 | 1048 | program_name, quotearg (Argv[optind])); | ||
1065 | 1049 | usage (stderr, 2); | ||
1066 | 1050 | } | ||
1067 | 1051 | } | ||
1068 | 1052 | } | ||
1069 | 1053 | } | ||
1070 | 1054 | |||
1071 | 1055 | /* Handle STRING (possibly negative if NEGATIVE_ALLOWED is nonzero) | ||
1072 | 1056 | of type ARGTYPE_MSGID by converting it to an integer, | ||
1073 | 1057 | returning the result. */ | ||
1074 | 1058 | static int | ||
1075 | 1059 | numeric_string (char const *string, | ||
1076 | 1060 | bool negative_allowed, | ||
1077 | 1061 | char const *argtype_msgid) | ||
1078 | 1062 | { | ||
1079 | 1063 | int value = 0; | ||
1080 | 1064 | char const *p = string; | ||
1081 | 1065 | int sign = *p == '-' ? -1 : 1; | ||
1082 | 1066 | |||
1083 | 1067 | p += *p == '-' || *p == '+'; | ||
1084 | 1068 | |||
1085 | 1069 | do | ||
1086 | 1070 | { | ||
1087 | 1071 | int v10 = value * 10; | ||
1088 | 1072 | int digit = *p - '0'; | ||
1089 | 1073 | int signed_digit = sign * digit; | ||
1090 | 1074 | int next_value = v10 + signed_digit; | ||
1091 | 1075 | |||
1092 | 1076 | if (9 < (unsigned) digit) | ||
1093 | 1077 | fatal ("%s %s is not a number", argtype_msgid, quotearg (string)); | ||
1094 | 1078 | |||
1095 | 1079 | if (v10 / 10 != value || (next_value < v10) != (signed_digit < 0)) | ||
1096 | 1080 | fatal ("%s %s is too large", argtype_msgid, quotearg (string)); | ||
1097 | 1081 | |||
1098 | 1082 | value = next_value; | ||
1099 | 1083 | } | ||
1100 | 1084 | while (*++p); | ||
1101 | 1085 | |||
1102 | 1086 | if (value < 0 && ! negative_allowed) | ||
1103 | 1087 | fatal ("%s %s is negative", argtype_msgid, quotearg (string)); | ||
1104 | 1088 | |||
1105 | 1089 | return value; | ||
1106 | 1090 | } | ||
1107 | 1091 | |||
1108 | 1092 | /* Attempt to find the right place to apply this hunk of patch. */ | ||
1109 | 1093 | |||
1110 | 1094 | static lin | ||
1111 | 1095 | locate_hunk (lin fuzz) | ||
1112 | 1096 | { | ||
1113 | 1097 | lin first_guess = pch_first () + in_offset; | ||
1114 | 1098 | lin offset; | ||
1115 | 1099 | lin pat_lines = pch_ptrn_lines(); | ||
1116 | 1100 | lin prefix_context = pch_prefix_context (); | ||
1117 | 1101 | lin suffix_context = pch_suffix_context (); | ||
1118 | 1102 | lin context = (prefix_context < suffix_context | ||
1119 | 1103 | ? suffix_context : prefix_context); | ||
1120 | 1104 | lin prefix_fuzz = fuzz + prefix_context - context; | ||
1121 | 1105 | lin suffix_fuzz = fuzz + suffix_context - context; | ||
1122 | 1106 | lin max_where = input_lines - (pat_lines - suffix_fuzz) + 1; | ||
1123 | 1107 | lin min_where = last_frozen_line + 1 - (prefix_context - prefix_fuzz); | ||
1124 | 1108 | lin max_pos_offset = max_where - first_guess; | ||
1125 | 1109 | lin max_neg_offset = first_guess - min_where; | ||
1126 | 1110 | lin max_offset = (max_pos_offset < max_neg_offset | ||
1127 | 1111 | ? max_neg_offset : max_pos_offset); | ||
1128 | 1112 | |||
1129 | 1113 | if (!pat_lines) /* null range matches always */ | ||
1130 | 1114 | return first_guess; | ||
1131 | 1115 | |||
1132 | 1116 | /* Do not try lines <= 0. */ | ||
1133 | 1117 | if (first_guess <= max_neg_offset) | ||
1134 | 1118 | max_neg_offset = first_guess - 1; | ||
1135 | 1119 | |||
1136 | 1120 | if (prefix_fuzz < 0 && pch_first () <= 1) | ||
1137 | 1121 | { | ||
1138 | 1122 | /* Can only match start of file. */ | ||
1139 | 1123 | |||
1140 | 1124 | if (suffix_fuzz < 0) | ||
1141 | 1125 | /* Can only match entire file. */ | ||
1142 | 1126 | if (pat_lines != input_lines || prefix_context < last_frozen_line) | ||
1143 | 1127 | return 0; | ||
1144 | 1128 | |||
1145 | 1129 | offset = 1 - first_guess; | ||
1146 | 1130 | if (last_frozen_line <= prefix_context | ||
1147 | 1131 | && offset <= max_pos_offset | ||
1148 | 1132 | && patch_match (first_guess, offset, 0, suffix_fuzz)) | ||
1149 | 1133 | { | ||
1150 | 1134 | in_offset += offset; | ||
1151 | 1135 | return first_guess + offset; | ||
1152 | 1136 | } | ||
1153 | 1137 | else | ||
1154 | 1138 | return 0; | ||
1155 | 1139 | } | ||
1156 | 1140 | else if (prefix_fuzz < 0) | ||
1157 | 1141 | prefix_fuzz = 0; | ||
1158 | 1142 | |||
1159 | 1143 | if (suffix_fuzz < 0) | ||
1160 | 1144 | { | ||
1161 | 1145 | /* Can only match end of file. */ | ||
1162 | 1146 | offset = first_guess - (input_lines - pat_lines + 1); | ||
1163 | 1147 | if (offset <= max_neg_offset | ||
1164 | 1148 | && patch_match (first_guess, -offset, prefix_fuzz, 0)) | ||
1165 | 1149 | { | ||
1166 | 1150 | in_offset -= offset; | ||
1167 | 1151 | return first_guess - offset; | ||
1168 | 1152 | } | ||
1169 | 1153 | else | ||
1170 | 1154 | return 0; | ||
1171 | 1155 | } | ||
1172 | 1156 | |||
1173 | 1157 | for (offset = 0; offset <= max_offset; offset++) { | ||
1174 | 1158 | char numbuf0[LINENUM_LENGTH_BOUND + 1]; | ||
1175 | 1159 | char numbuf1[LINENUM_LENGTH_BOUND + 1]; | ||
1176 | 1160 | if (offset <= max_pos_offset | ||
1177 | 1161 | && patch_match (first_guess, offset, prefix_fuzz, suffix_fuzz)) { | ||
1178 | 1162 | if (debug & 1) | ||
1179 | 1163 | say ("Offset changing from %s to %s\n", | ||
1180 | 1164 | format_linenum (numbuf0, in_offset), | ||
1181 | 1165 | format_linenum (numbuf1, in_offset + offset)); | ||
1182 | 1166 | in_offset += offset; | ||
1183 | 1167 | return first_guess+offset; | ||
1184 | 1168 | } | ||
1185 | 1169 | if (0 < offset && offset <= max_neg_offset | ||
1186 | 1170 | && patch_match (first_guess, -offset, prefix_fuzz, suffix_fuzz)) { | ||
1187 | 1171 | if (debug & 1) | ||
1188 | 1172 | say ("Offset changing from %s to %s\n", | ||
1189 | 1173 | format_linenum (numbuf0, in_offset), | ||
1190 | 1174 | format_linenum (numbuf1, in_offset - offset)); | ||
1191 | 1175 | in_offset -= offset; | ||
1192 | 1176 | return first_guess-offset; | ||
1193 | 1177 | } | ||
1194 | 1178 | } | ||
1195 | 1179 | return 0; | ||
1196 | 1180 | } | ||
1197 | 1181 | |||
1198 | 1182 | static void __attribute__ ((noreturn)) | ||
1199 | 1183 | mangled_patch (lin old, lin new) | ||
1200 | 1184 | { | ||
1201 | 1185 | char numbuf0[LINENUM_LENGTH_BOUND + 1]; | ||
1202 | 1186 | char numbuf1[LINENUM_LENGTH_BOUND + 1]; | ||
1203 | 1187 | if (debug & 1) | ||
1204 | 1188 | say ("oldchar = '%c', newchar = '%c'\n", | ||
1205 | 1189 | pch_char (old), pch_char (new)); | ||
1206 | 1190 | fatal ("Out-of-sync patch, lines %s,%s -- mangled text or line numbers, " | ||
1207 | 1191 | "maybe?", | ||
1208 | 1192 | format_linenum (numbuf0, pch_hunk_beg () + old), | ||
1209 | 1193 | format_linenum (numbuf1, pch_hunk_beg () + new)); | ||
1210 | 1194 | } | ||
1211 | 1195 | |||
1212 | 1196 | /* Output a line number range in unified format. */ | ||
1213 | 1197 | |||
1214 | 1198 | static void | ||
1215 | 1199 | print_unidiff_range (FILE *fp, lin start, lin count) | ||
1216 | 1200 | { | ||
1217 | 1201 | char numbuf0[LINENUM_LENGTH_BOUND + 1]; | ||
1218 | 1202 | char numbuf1[LINENUM_LENGTH_BOUND + 1]; | ||
1219 | 1203 | |||
1220 | 1204 | switch (count) | ||
1221 | 1205 | { | ||
1222 | 1206 | case 0: | ||
1223 | 1207 | fprintf (fp, "%s,0", format_linenum (numbuf0, start - 1)); | ||
1224 | 1208 | break; | ||
1225 | 1209 | |||
1226 | 1210 | case 1: | ||
1227 | 1211 | fprintf (fp, "%s", format_linenum (numbuf0, start)); | ||
1228 | 1212 | break; | ||
1229 | 1213 | |||
1230 | 1214 | default: | ||
1231 | 1215 | fprintf (fp, "%s,%s", | ||
1232 | 1216 | format_linenum (numbuf0, start), | ||
1233 | 1217 | format_linenum (numbuf1, count)); | ||
1234 | 1218 | break; | ||
1235 | 1219 | } | ||
1236 | 1220 | } | ||
1237 | 1221 | |||
1238 | 1222 | static void | ||
1239 | 1223 | print_header_line (FILE *fp, const char *tag, bool reverse) | ||
1240 | 1224 | { | ||
1241 | 1225 | const char *name = pch_name (reverse); | ||
1242 | 1226 | const char *timestr = pch_timestr (reverse); | ||
1243 | 1227 | |||
1244 | 1228 | fprintf (fp, "%s %s%s\n", tag, name ? name : "/dev/null", | ||
1245 | 1229 | timestr ? timestr : ""); | ||
1246 | 1230 | } | ||
1247 | 1231 | |||
1248 | 1232 | /* Produce unified reject files */ | ||
1249 | 1233 | |||
1250 | 1234 | static void | ||
1251 | 1235 | abort_hunk_unified (bool header, bool reverse) | ||
1252 | 1236 | { | ||
1253 | 1237 | lin old = 1; | ||
1254 | 1238 | lin lastline = pch_ptrn_lines (); | ||
1255 | 1239 | lin new = lastline + 1; | ||
1256 | 1240 | |||
1257 | 1241 | if (header) | ||
1258 | 1242 | { | ||
1259 | 1243 | if (pch_name (INDEX)) | ||
1260 | 1244 | fprintf(rejfp, "Index: %s\n", pch_name (INDEX)); | ||
1261 | 1245 | print_header_line (rejfp, "---", reverse); | ||
1262 | 1246 | print_header_line (rejfp, "+++", ! reverse); | ||
1263 | 1247 | } | ||
1264 | 1248 | |||
1265 | 1249 | /* Add out_offset to guess the same as the previous successful hunk. */ | ||
1266 | 1250 | fprintf (rejfp, "@@ -"); | ||
1267 | 1251 | print_unidiff_range (rejfp, pch_first () + out_offset, lastline); | ||
1268 | 1252 | fprintf (rejfp, " +"); | ||
1269 | 1253 | print_unidiff_range (rejfp, pch_newfirst () + out_offset, pch_repl_lines ()); | ||
1270 | 1254 | fprintf (rejfp, " @@\n"); | ||
1271 | 1255 | |||
1272 | 1256 | while (pch_char (new) == '=' || pch_char (new) == '\n') | ||
1273 | 1257 | new++; | ||
1274 | 1258 | |||
1275 | 1259 | if (diff_type != UNI_DIFF) | ||
1276 | 1260 | pch_normalize (UNI_DIFF); | ||
1277 | 1261 | |||
1278 | 1262 | for (; ; old++, new++) | ||
1279 | 1263 | { | ||
1280 | 1264 | for (; pch_char (old) == '-'; old++) | ||
1281 | 1265 | { | ||
1282 | 1266 | fputc ('-', rejfp); | ||
1283 | 1267 | pch_write_line (old, rejfp); | ||
1284 | 1268 | } | ||
1285 | 1269 | for (; pch_char (new) == '+'; new++) | ||
1286 | 1270 | { | ||
1287 | 1271 | fputc ('+', rejfp); | ||
1288 | 1272 | pch_write_line (new, rejfp); | ||
1289 | 1273 | } | ||
1290 | 1274 | |||
1291 | 1275 | if (old > lastline) | ||
1292 | 1276 | break; | ||
1293 | 1277 | |||
1294 | 1278 | if (pch_char (new) != pch_char (old)) | ||
1295 | 1279 | mangled_patch (old, new); | ||
1296 | 1280 | |||
1297 | 1281 | fputc (' ', rejfp); | ||
1298 | 1282 | pch_write_line (old, rejfp); | ||
1299 | 1283 | } | ||
1300 | 1284 | if (pch_char (new) != '^') | ||
1301 | 1285 | mangled_patch (old, new); | ||
1302 | 1286 | } | ||
1303 | 1287 | |||
1304 | 1288 | /* Output the rejected patch in context format. */ | ||
1305 | 1289 | |||
1306 | 1290 | static void | ||
1307 | 1291 | abort_hunk_context (bool header, bool reverse) | ||
1308 | 1292 | { | ||
1309 | 1293 | lin i; | ||
1310 | 1294 | lin pat_end = pch_end (); | ||
1311 | 1295 | /* add in out_offset to guess the same as the previous successful hunk */ | ||
1312 | 1296 | lin oldfirst = pch_first() + out_offset; | ||
1313 | 1297 | lin newfirst = pch_newfirst() + out_offset; | ||
1314 | 1298 | lin oldlast = oldfirst + pch_ptrn_lines() - 1; | ||
1315 | 1299 | lin newlast = newfirst + pch_repl_lines() - 1; | ||
1316 | 1300 | char const *stars = | ||
1317 | 1301 | (int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ****" : ""; | ||
1318 | 1302 | char const *minuses = | ||
1319 | 1303 | (int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ----" : " -----"; | ||
1320 | 1304 | char const *c_function = pch_c_function(); | ||
1321 | 1305 | |||
1322 | 1306 | if (diff_type == UNI_DIFF) | ||
1323 | 1307 | pch_normalize (NEW_CONTEXT_DIFF); | ||
1324 | 1308 | |||
1325 | 1309 | if (header) | ||
1326 | 1310 | { | ||
1327 | 1311 | if (pch_name (INDEX)) | ||
1328 | 1312 | fprintf(rejfp, "Index: %s\n", pch_name (INDEX)); | ||
1329 | 1313 | print_header_line (rejfp, "***", reverse); | ||
1330 | 1314 | print_header_line (rejfp, "---", ! reverse); | ||
1331 | 1315 | } | ||
1332 | 1316 | fprintf(rejfp, "***************%s\n", c_function ? c_function : ""); | ||
1333 | 1317 | for (i=0; i<=pat_end; i++) { | ||
1334 | 1318 | char numbuf0[LINENUM_LENGTH_BOUND + 1]; | ||
1335 | 1319 | char numbuf1[LINENUM_LENGTH_BOUND + 1]; | ||
1336 | 1320 | switch (pch_char(i)) { | ||
1337 | 1321 | case '*': | ||
1338 | 1322 | if (oldlast < oldfirst) | ||
1339 | 1323 | fprintf(rejfp, "*** 0%s\n", stars); | ||
1340 | 1324 | else if (oldlast == oldfirst) | ||
1341 | 1325 | fprintf (rejfp, "*** %s%s\n", | ||
1342 | 1326 | format_linenum (numbuf0, oldfirst), stars); | ||
1343 | 1327 | else | ||
1344 | 1328 | fprintf (rejfp, "*** %s,%s%s\n", | ||
1345 | 1329 | format_linenum (numbuf0, oldfirst), | ||
1346 | 1330 | format_linenum (numbuf1, oldlast), stars); | ||
1347 | 1331 | break; | ||
1348 | 1332 | case '=': | ||
1349 | 1333 | if (newlast < newfirst) | ||
1350 | 1334 | fprintf(rejfp, "--- 0%s\n", minuses); | ||
1351 | 1335 | else if (newlast == newfirst) | ||
1352 | 1336 | fprintf (rejfp, "--- %s%s\n", | ||
1353 | 1337 | format_linenum (numbuf0, newfirst), minuses); | ||
1354 | 1338 | else | ||
1355 | 1339 | fprintf (rejfp, "--- %s,%s%s\n", | ||
1356 | 1340 | format_linenum (numbuf0, newfirst), | ||
1357 | 1341 | format_linenum (numbuf1, newlast), minuses); | ||
1358 | 1342 | break; | ||
1359 | 1343 | case ' ': case '-': case '+': case '!': | ||
1360 | 1344 | fprintf (rejfp, "%c ", pch_char (i)); | ||
1361 | 1345 | /* fall into */ | ||
1362 | 1346 | case '\n': | ||
1363 | 1347 | pch_write_line (i, rejfp); | ||
1364 | 1348 | break; | ||
1365 | 1349 | default: | ||
1366 | 1350 | fatal ("fatal internal error in abort_hunk_context"); | ||
1367 | 1351 | } | ||
1368 | 1352 | if (ferror (rejfp)) | ||
1369 | 1353 | write_fatal (); | ||
1370 | 1354 | } | ||
1371 | 1355 | } | ||
1372 | 1356 | |||
1373 | 1357 | /* Output the rejected hunk. */ | ||
1374 | 1358 | |||
1375 | 1359 | static void | ||
1376 | 1360 | abort_hunk (char const *outname, bool header, bool reverse) | ||
1377 | 1361 | { | ||
1378 | 1362 | if (! TMPREJNAME_needs_removal) | ||
1379 | 1363 | init_reject (outname); | ||
1380 | 1364 | if (reject_format == UNI_DIFF | ||
1381 | 1365 | || (reject_format == NO_DIFF && diff_type == UNI_DIFF)) | ||
1382 | 1366 | abort_hunk_unified (header, reverse); | ||
1383 | 1367 | else | ||
1384 | 1368 | abort_hunk_context (header, reverse); | ||
1385 | 1369 | } | ||
1386 | 1370 | |||
1387 | 1371 | /* We found where to apply it (we hope), so do it. */ | ||
1388 | 1372 | |||
1389 | 1373 | static bool | ||
1390 | 1374 | apply_hunk (struct outstate *outstate, lin where) | ||
1391 | 1375 | { | ||
1392 | 1376 | lin old = 1; | ||
1393 | 1377 | lin lastline = pch_ptrn_lines (); | ||
1394 | 1378 | lin new = lastline+1; | ||
1395 | 1379 | enum {OUTSIDE, IN_IFNDEF, IN_IFDEF, IN_ELSE} def_state = OUTSIDE; | ||
1396 | 1380 | char const *R_do_defines = do_defines; | ||
1397 | 1381 | lin pat_end = pch_end (); | ||
1398 | 1382 | FILE *fp = outstate->ofp; | ||
1399 | 1383 | |||
1400 | 1384 | where--; | ||
1401 | 1385 | while (pch_char(new) == '=' || pch_char(new) == '\n') | ||
1402 | 1386 | new++; | ||
1403 | 1387 | |||
1404 | 1388 | while (old <= lastline) { | ||
1405 | 1389 | if (pch_char(old) == '-') { | ||
1406 | 1390 | assert (outstate->after_newline); | ||
1407 | 1391 | if (! copy_till (outstate, where + old - 1)) | ||
1408 | 1392 | return false; | ||
1409 | 1393 | if (R_do_defines) { | ||
1410 | 1394 | if (def_state == OUTSIDE) { | ||
1411 | 1395 | fprintf (fp, outstate->after_newline + not_defined, | ||
1412 | 1396 | R_do_defines); | ||
1413 | 1397 | def_state = IN_IFNDEF; | ||
1414 | 1398 | } | ||
1415 | 1399 | else if (def_state == IN_IFDEF) { | ||
1416 | 1400 | fputs (outstate->after_newline + else_defined, fp); | ||
1417 | 1401 | def_state = IN_ELSE; | ||
1418 | 1402 | } | ||
1419 | 1403 | if (ferror (fp)) | ||
1420 | 1404 | write_fatal (); | ||
1421 | 1405 | outstate->after_newline = pch_write_line (old, fp); | ||
1422 | 1406 | outstate->zero_output = false; | ||
1423 | 1407 | } | ||
1424 | 1408 | last_frozen_line++; | ||
1425 | 1409 | old++; | ||
1426 | 1410 | } | ||
1427 | 1411 | else if (new > pat_end) { | ||
1428 | 1412 | break; | ||
1429 | 1413 | } | ||
1430 | 1414 | else if (pch_char(new) == '+') { | ||
1431 | 1415 | if (! copy_till (outstate, where + old - 1)) | ||
1432 | 1416 | return false; | ||
1433 | 1417 | if (R_do_defines) { | ||
1434 | 1418 | if (def_state == IN_IFNDEF) { | ||
1435 | 1419 | fputs (outstate->after_newline + else_defined, fp); | ||
1436 | 1420 | def_state = IN_ELSE; | ||
1437 | 1421 | } | ||
1438 | 1422 | else if (def_state == OUTSIDE) { | ||
1439 | 1423 | fprintf (fp, outstate->after_newline + if_defined, | ||
1440 | 1424 | R_do_defines); | ||
1441 | 1425 | def_state = IN_IFDEF; | ||
1442 | 1426 | } | ||
1443 | 1427 | if (ferror (fp)) | ||
1444 | 1428 | write_fatal (); | ||
1445 | 1429 | } | ||
1446 | 1430 | outstate->after_newline = pch_write_line (new, fp); | ||
1447 | 1431 | outstate->zero_output = false; | ||
1448 | 1432 | new++; | ||
1449 | 1433 | } | ||
1450 | 1434 | else if (pch_char(new) != pch_char(old)) | ||
1451 | 1435 | mangled_patch (old, new); | ||
1452 | 1436 | else if (pch_char(new) == '!') { | ||
1453 | 1437 | assert (outstate->after_newline); | ||
1454 | 1438 | if (! copy_till (outstate, where + old - 1)) | ||
1455 | 1439 | return false; | ||
1456 | 1440 | assert (outstate->after_newline); | ||
1457 | 1441 | if (R_do_defines) { | ||
1458 | 1442 | fprintf (fp, 1 + not_defined, R_do_defines); | ||
1459 | 1443 | if (ferror (fp)) | ||
1460 | 1444 | write_fatal (); | ||
1461 | 1445 | def_state = IN_IFNDEF; | ||
1462 | 1446 | } | ||
1463 | 1447 | |||
1464 | 1448 | do | ||
1465 | 1449 | { | ||
1466 | 1450 | if (R_do_defines) { | ||
1467 | 1451 | outstate->after_newline = pch_write_line (old, fp); | ||
1468 | 1452 | } | ||
1469 | 1453 | last_frozen_line++; | ||
1470 | 1454 | old++; | ||
1471 | 1455 | } | ||
1472 | 1456 | while (pch_char (old) == '!'); | ||
1473 | 1457 | |||
1474 | 1458 | if (R_do_defines) { | ||
1475 | 1459 | fputs (outstate->after_newline + else_defined, fp); | ||
1476 | 1460 | if (ferror (fp)) | ||
1477 | 1461 | write_fatal (); | ||
1478 | 1462 | def_state = IN_ELSE; | ||
1479 | 1463 | } | ||
1480 | 1464 | |||
1481 | 1465 | do | ||
1482 | 1466 | { | ||
1483 | 1467 | outstate->after_newline = pch_write_line (new, fp); | ||
1484 | 1468 | new++; | ||
1485 | 1469 | } | ||
1486 | 1470 | while (pch_char (new) == '!'); | ||
1487 | 1471 | outstate->zero_output = false; | ||
1488 | 1472 | } | ||
1489 | 1473 | else { | ||
1490 | 1474 | assert(pch_char(new) == ' '); | ||
1491 | 1475 | old++; | ||
1492 | 1476 | new++; | ||
1493 | 1477 | if (R_do_defines && def_state != OUTSIDE) { | ||
1494 | 1478 | fputs (outstate->after_newline + end_defined, fp); | ||
1495 | 1479 | if (ferror (fp)) | ||
1496 | 1480 | write_fatal (); | ||
1497 | 1481 | outstate->after_newline = true; | ||
1498 | 1482 | def_state = OUTSIDE; | ||
1499 | 1483 | } | ||
1500 | 1484 | } | ||
1501 | 1485 | } | ||
1502 | 1486 | if (new <= pat_end && pch_char(new) == '+') { | ||
1503 | 1487 | if (! copy_till (outstate, where + old - 1)) | ||
1504 | 1488 | return false; | ||
1505 | 1489 | if (R_do_defines) { | ||
1506 | 1490 | if (def_state == OUTSIDE) { | ||
1507 | 1491 | fprintf (fp, outstate->after_newline + if_defined, | ||
1508 | 1492 | R_do_defines); | ||
1509 | 1493 | def_state = IN_IFDEF; | ||
1510 | 1494 | } | ||
1511 | 1495 | else if (def_state == IN_IFNDEF) { | ||
1512 | 1496 | fputs (outstate->after_newline + else_defined, fp); | ||
1513 | 1497 | def_state = IN_ELSE; | ||
1514 | 1498 | } | ||
1515 | 1499 | if (ferror (fp)) | ||
1516 | 1500 | write_fatal (); | ||
1517 | 1501 | outstate->zero_output = false; | ||
1518 | 1502 | } | ||
1519 | 1503 | |||
1520 | 1504 | do | ||
1521 | 1505 | { | ||
1522 | 1506 | if (! outstate->after_newline && putc ('\n', fp) == EOF) | ||
1523 | 1507 | write_fatal (); | ||
1524 | 1508 | outstate->after_newline = pch_write_line (new, fp); | ||
1525 | 1509 | outstate->zero_output = false; | ||
1526 | 1510 | new++; | ||
1527 | 1511 | } | ||
1528 | 1512 | while (new <= pat_end && pch_char (new) == '+'); | ||
1529 | 1513 | } | ||
1530 | 1514 | if (R_do_defines && def_state != OUTSIDE) { | ||
1531 | 1515 | fputs (outstate->after_newline + end_defined, fp); | ||
1532 | 1516 | if (ferror (fp)) | ||
1533 | 1517 | write_fatal (); | ||
1534 | 1518 | outstate->after_newline = true; | ||
1535 | 1519 | } | ||
1536 | 1520 | out_offset += pch_repl_lines() - pch_ptrn_lines (); | ||
1537 | 1521 | return true; | ||
1538 | 1522 | } | ||
1539 | 1523 | |||
1540 | 1524 | /* Create an output file. */ | ||
1541 | 1525 | |||
1542 | 1526 | static FILE * | ||
1543 | 1527 | create_output_file (char const *name, int open_flags) | ||
1544 | 1528 | { | ||
1545 | 1529 | int fd = create_file (name, O_WRONLY | binary_transput | open_flags, | ||
1546 | 1530 | instat.st_mode, true); | ||
1547 | 1531 | FILE *f = fdopen (fd, binary_transput ? "wb" : "w"); | ||
1548 | 1532 | if (! f) | ||
1549 | 1533 | pfatal ("Can't create file %s", quotearg (name)); | ||
1550 | 1534 | return f; | ||
1551 | 1535 | } | ||
1552 | 1536 | |||
1553 | 1537 | /* Open the new file. */ | ||
1554 | 1538 | |||
1555 | 1539 | static void | ||
1556 | 1540 | init_output (struct outstate *outstate) | ||
1557 | 1541 | { | ||
1558 | 1542 | outstate->ofp = NULL; | ||
1559 | 1543 | outstate->after_newline = true; | ||
1560 | 1544 | outstate->zero_output = true; | ||
1561 | 1545 | } | ||
1562 | 1546 | |||
1563 | 1547 | static FILE * | ||
1564 | 1548 | open_outfile (char const *name) | ||
1565 | 1549 | { | ||
1566 | 1550 | if (strcmp (name, "-") != 0) | ||
1567 | 1551 | return create_output_file (name, 0); | ||
1568 | 1552 | else | ||
1569 | 1553 | { | ||
1570 | 1554 | FILE *ofp; | ||
1571 | 1555 | int stdout_dup = dup (fileno (stdout)); | ||
1572 | 1556 | if (stdout_dup == -1) | ||
1573 | 1557 | pfatal ("Failed to duplicate standard output"); | ||
1574 | 1558 | ofp = fdopen (stdout_dup, "a"); | ||
1575 | 1559 | if (! ofp) | ||
1576 | 1560 | pfatal ("Failed to duplicate standard output"); | ||
1577 | 1561 | if (dup2 (fileno (stderr), fileno (stdout)) == -1) | ||
1578 | 1562 | pfatal ("Failed to redirect messages to standard error"); | ||
1579 | 1563 | /* FIXME: Do we need to switch stdout_dup into O_BINARY mode here? */ | ||
1580 | 1564 | return ofp; | ||
1581 | 1565 | } | ||
1582 | 1566 | } | ||
1583 | 1567 | |||
1584 | 1568 | /* Open a file to put hunks we can't locate. */ | ||
1585 | 1569 | |||
1586 | 1570 | static void | ||
1587 | 1571 | init_reject (char const *outname) | ||
1588 | 1572 | { | ||
1589 | 1573 | int fd; | ||
1590 | 1574 | fd = make_tempfile (&TMPREJNAME, 'r', outname, O_WRONLY | binary_transput, | ||
1591 | 1575 | 0666); | ||
1592 | 1576 | TMPREJNAME_needs_removal = true; | ||
1593 | 1577 | rejfp = fdopen (fd, binary_transput ? "wb" : "w"); | ||
1594 | 1578 | if (! rejfp) | ||
1595 | 1579 | pfatal ("Can't open stream for file %s", quotearg (TMPREJNAME)); | ||
1596 | 1580 | } | ||
1597 | 1581 | |||
1598 | 1582 | /* Copy input file to output, up to wherever hunk is to be applied. */ | ||
1599 | 1583 | |||
1600 | 1584 | bool | ||
1601 | 1585 | copy_till (struct outstate *outstate, lin lastline) | ||
1602 | 1586 | { | ||
1603 | 1587 | lin R_last_frozen_line = last_frozen_line; | ||
1604 | 1588 | FILE *fp = outstate->ofp; | ||
1605 | 1589 | char const *s; | ||
1606 | 1590 | size_t size; | ||
1607 | 1591 | |||
1608 | 1592 | if (R_last_frozen_line > lastline) | ||
1609 | 1593 | { | ||
1610 | 1594 | say ("misordered hunks! output would be garbled\n"); | ||
1611 | 1595 | return false; | ||
1612 | 1596 | } | ||
1613 | 1597 | while (R_last_frozen_line < lastline) | ||
1614 | 1598 | { | ||
1615 | 1599 | s = ifetch (++R_last_frozen_line, false, &size); | ||
1616 | 1600 | if (size) | ||
1617 | 1601 | { | ||
1618 | 1602 | if ((! outstate->after_newline && putc ('\n', fp) == EOF) | ||
1619 | 1603 | || ! fwrite (s, sizeof *s, size, fp)) | ||
1620 | 1604 | write_fatal (); | ||
1621 | 1605 | outstate->after_newline = s[size - 1] == '\n'; | ||
1622 | 1606 | outstate->zero_output = false; | ||
1623 | 1607 | } | ||
1624 | 1608 | } | ||
1625 | 1609 | last_frozen_line = R_last_frozen_line; | ||
1626 | 1610 | return true; | ||
1627 | 1611 | } | ||
1628 | 1612 | |||
1629 | 1613 | /* Finish copying the input file to the output file. */ | ||
1630 | 1614 | |||
1631 | 1615 | static bool | ||
1632 | 1616 | spew_output (struct outstate *outstate, struct stat *st) | ||
1633 | 1617 | { | ||
1634 | 1618 | if (debug & 256) | ||
1635 | 1619 | { | ||
1636 | 1620 | char numbuf0[LINENUM_LENGTH_BOUND + 1]; | ||
1637 | 1621 | char numbuf1[LINENUM_LENGTH_BOUND + 1]; | ||
1638 | 1622 | say ("il=%s lfl=%s\n", | ||
1639 | 1623 | format_linenum (numbuf0, input_lines), | ||
1640 | 1624 | format_linenum (numbuf1, last_frozen_line)); | ||
1641 | 1625 | } | ||
1642 | 1626 | |||
1643 | 1627 | if (last_frozen_line < input_lines) | ||
1644 | 1628 | if (! copy_till (outstate, input_lines)) | ||
1645 | 1629 | return false; | ||
1646 | 1630 | |||
1647 | 1631 | if (outstate->ofp && ! outfile) | ||
1648 | 1632 | { | ||
1649 | 1633 | if (fflush (outstate->ofp) != 0 | ||
1650 | 1634 | || fstat (fileno (outstate->ofp), st) != 0 | ||
1651 | 1635 | || fclose (outstate->ofp) != 0) | ||
1652 | 1636 | write_fatal (); | ||
1653 | 1637 | outstate->ofp = 0; | ||
1654 | 1638 | } | ||
1655 | 1639 | |||
1656 | 1640 | return true; | ||
1657 | 1641 | } | ||
1658 | 1642 | |||
1659 | 1643 | /* Does the patch pattern match at line base+offset? */ | ||
1660 | 1644 | |||
1661 | 1645 | static bool | ||
1662 | 1646 | patch_match (lin base, lin offset, lin prefix_fuzz, lin suffix_fuzz) | ||
1663 | 1647 | { | ||
1664 | 1648 | lin pline = 1 + prefix_fuzz; | ||
1665 | 1649 | lin iline; | ||
1666 | 1650 | lin pat_lines = pch_ptrn_lines () - suffix_fuzz; | ||
1667 | 1651 | size_t size; | ||
1668 | 1652 | char const *p; | ||
1669 | 1653 | |||
1670 | 1654 | for (iline=base+offset+prefix_fuzz; pline <= pat_lines; pline++,iline++) { | ||
1671 | 1655 | p = ifetch (iline, offset >= 0, &size); | ||
1672 | 1656 | if (canonicalize) { | ||
1673 | 1657 | if (!similar(p, size, | ||
1674 | 1658 | pfetch(pline), | ||
1675 | 1659 | pch_line_len(pline) )) | ||
1676 | 1660 | return false; | ||
1677 | 1661 | } | ||
1678 | 1662 | else if (size != pch_line_len (pline) | ||
1679 | 1663 | || memcmp (p, pfetch (pline), size) != 0) | ||
1680 | 1664 | return false; | ||
1681 | 1665 | } | ||
1682 | 1666 | return true; | ||
1683 | 1667 | } | ||
1684 | 1668 | |||
1685 | 1669 | /* Check if the line endings in the input file and in the patch differ. */ | ||
1686 | 1670 | |||
1687 | 1671 | static bool | ||
1688 | 1672 | check_line_endings (lin where) | ||
1689 | 1673 | { | ||
1690 | 1674 | char const *p; | ||
1691 | 1675 | size_t size; | ||
1692 | 1676 | bool input_crlf, patch_crlf; | ||
1693 | 1677 | |||
1694 | 1678 | p = pfetch (1); | ||
1695 | 1679 | size = pch_line_len (1); | ||
1696 | 1680 | if (! size) | ||
1697 | 1681 | return false; | ||
1698 | 1682 | patch_crlf = size >= 2 && p[size - 2] == '\r' && p[size - 1] == '\n'; | ||
1699 | 1683 | |||
1700 | 1684 | if (! input_lines) | ||
1701 | 1685 | return false; | ||
1702 | 1686 | if (where > input_lines) | ||
1703 | 1687 | where = input_lines; | ||
1704 | 1688 | p = ifetch (where, false, &size); | ||
1705 | 1689 | if (! size) | ||
1706 | 1690 | return false; | ||
1707 | 1691 | input_crlf = size >= 2 && p[size - 2] == '\r' && p[size - 1] == '\n'; | ||
1708 | 1692 | |||
1709 | 1693 | return patch_crlf != input_crlf; | ||
1710 | 1694 | } | ||
1711 | 1695 | |||
1712 | 1696 | /* Do two lines match with canonicalized white space? */ | ||
1713 | 1697 | |||
1714 | 1698 | bool | ||
1715 | 1699 | similar (char const *a, size_t alen, char const *b, size_t blen) | ||
1716 | 1700 | { | ||
1717 | 1701 | /* Ignore presence or absence of trailing newlines. */ | ||
1718 | 1702 | alen -= alen && a[alen - 1] == '\n'; | ||
1719 | 1703 | blen -= blen && b[blen - 1] == '\n'; | ||
1720 | 1704 | |||
1721 | 1705 | for (;;) | ||
1722 | 1706 | { | ||
1723 | 1707 | if (!blen || (*b == ' ' || *b == '\t')) | ||
1724 | 1708 | { | ||
1725 | 1709 | while (blen && (*b == ' ' || *b == '\t')) | ||
1726 | 1710 | b++, blen--; | ||
1727 | 1711 | if (alen) | ||
1728 | 1712 | { | ||
1729 | 1713 | if (!(*a == ' ' || *a == '\t')) | ||
1730 | 1714 | return false; | ||
1731 | 1715 | do a++, alen--; | ||
1732 | 1716 | while (alen && (*a == ' ' || *a == '\t')); | ||
1733 | 1717 | } | ||
1734 | 1718 | if (!alen || !blen) | ||
1735 | 1719 | return alen == blen; | ||
1736 | 1720 | } | ||
1737 | 1721 | else if (!alen || *a++ != *b++) | ||
1738 | 1722 | return false; | ||
1739 | 1723 | else | ||
1740 | 1724 | alen--, blen--; | ||
1741 | 1725 | } | ||
1742 | 1726 | } | ||
1743 | 1727 | |||
1744 | 1728 | /* Deferred deletion of files. */ | ||
1745 | 1729 | |||
1746 | 1730 | struct file_to_delete { | ||
1747 | 1731 | char *name; | ||
1748 | 1732 | struct stat st; | ||
1749 | 1733 | bool backup; | ||
1750 | 1734 | }; | ||
1751 | 1735 | |||
1752 | 1736 | static gl_list_t files_to_delete; | ||
1753 | 1737 | |||
1754 | 1738 | static void | ||
1755 | 1739 | init_files_to_delete (void) | ||
1756 | 1740 | { | ||
1757 | 1741 | files_to_delete = gl_list_create_empty (GL_LINKED_LIST, NULL, NULL, NULL, true); | ||
1758 | 1742 | } | ||
1759 | 1743 | |||
1760 | 1744 | static void | ||
1761 | 1745 | delete_file_later (const char *name, const struct stat *st, bool backup) | ||
1762 | 1746 | { | ||
1763 | 1747 | struct file_to_delete *file_to_delete; | ||
1764 | 1748 | struct stat st_tmp; | ||
1765 | 1749 | |||
1766 | 1750 | if (! st) | ||
1767 | 1751 | { | ||
1768 | 1752 | if (stat_file (name, &st_tmp) != 0) | ||
1769 | 1753 | pfatal ("Can't get file attributes of %s %s", "file", name); | ||
1770 | 1754 | st = &st_tmp; | ||
1771 | 1755 | } | ||
1772 | 1756 | file_to_delete = xmalloc (sizeof *file_to_delete); | ||
1773 | 1757 | file_to_delete->name = xstrdup (name); | ||
1774 | 1758 | file_to_delete->st = *st; | ||
1775 | 1759 | file_to_delete->backup = backup; | ||
1776 | 1760 | gl_list_add_last (files_to_delete, file_to_delete); | ||
1777 | 1761 | insert_file_id (st, DELETE_LATER); | ||
1778 | 1762 | } | ||
1779 | 1763 | |||
1780 | 1764 | static void | ||
1781 | 1765 | delete_files (void) | ||
1782 | 1766 | { | ||
1783 | 1767 | gl_list_iterator_t iter; | ||
1784 | 1768 | const void *elt; | ||
1785 | 1769 | |||
1786 | 1770 | iter = gl_list_iterator (files_to_delete); | ||
1787 | 1771 | while (gl_list_iterator_next (&iter, &elt, NULL)) | ||
1788 | 1772 | { | ||
1789 | 1773 | const struct file_to_delete *file_to_delete = elt; | ||
1790 | 1774 | |||
1791 | 1775 | if (lookup_file_id (&file_to_delete->st) == DELETE_LATER) | ||
1792 | 1776 | { | ||
1793 | 1777 | mode_t mode = file_to_delete->st.st_mode; | ||
1794 | 1778 | |||
1795 | 1779 | if (verbosity == VERBOSE) | ||
1796 | 1780 | say ("Removing %s %s\n", | ||
1797 | 1781 | S_ISLNK (mode) ? "symbolic link" : "file", | ||
1798 | 1782 | quotearg (file_to_delete->name)); | ||
1799 | 1783 | move_file (0, 0, 0, file_to_delete->name, mode, | ||
1800 | 1784 | file_to_delete->backup); | ||
1801 | 1785 | removedirs (file_to_delete->name); | ||
1802 | 1786 | } | ||
1803 | 1787 | } | ||
1804 | 1788 | gl_list_iterator_free (&iter); | ||
1805 | 1789 | } | ||
1806 | 1790 | |||
1807 | 1791 | /* Putting output files into place and removing them. */ | ||
1808 | 1792 | |||
1809 | 1793 | struct file_to_output { | ||
1810 | 1794 | char *from; | ||
1811 | 1795 | struct stat from_st; | ||
1812 | 1796 | char *to; | ||
1813 | 1797 | mode_t mode; | ||
1814 | 1798 | bool backup; | ||
1815 | 1799 | }; | ||
1816 | 1800 | |||
1817 | 1801 | static gl_list_t files_to_output; | ||
1818 | 1802 | |||
1819 | 1803 | static void | ||
1820 | 1804 | output_file_later (char const *from, bool *from_needs_removal, const struct stat *from_st, | ||
1821 | 1805 | char const *to, mode_t mode, bool backup) | ||
1822 | 1806 | { | ||
1823 | 1807 | struct file_to_output *file_to_output; | ||
1824 | 1808 | |||
1825 | 1809 | file_to_output = xmalloc (sizeof *file_to_output); | ||
1826 | 1810 | file_to_output->from = xstrdup (from); | ||
1827 | 1811 | file_to_output->from_st = *from_st; | ||
1828 | 1812 | file_to_output->to = to ? xstrdup (to) : NULL; | ||
1829 | 1813 | file_to_output->mode = mode; | ||
1830 | 1814 | file_to_output->backup = backup; | ||
1831 | 1815 | gl_list_add_last (files_to_output, file_to_output); | ||
1832 | 1816 | if (from_needs_removal) | ||
1833 | 1817 | *from_needs_removal = false; | ||
1834 | 1818 | } | ||
1835 | 1819 | |||
1836 | 1820 | static void | ||
1837 | 1821 | output_file_now (char const *from, bool *from_needs_removal, | ||
1838 | 1822 | const struct stat *from_st, char const *to, | ||
1839 | 1823 | mode_t mode, bool backup) | ||
1840 | 1824 | { | ||
1841 | 1825 | if (to == NULL) | ||
1842 | 1826 | { | ||
1843 | 1827 | if (backup) | ||
1844 | 1828 | create_backup (from, from_st, true); | ||
1845 | 1829 | } | ||
1846 | 1830 | else | ||
1847 | 1831 | { | ||
1848 | 1832 | assert (from_st->st_size != -1); | ||
1849 | 1833 | move_file (from, from_needs_removal, from_st, to, mode, backup); | ||
1850 | 1834 | } | ||
1851 | 1835 | } | ||
1852 | 1836 | |||
1853 | 1837 | static void | ||
1854 | 1838 | output_file (char const *from, bool *from_needs_removal, | ||
1855 | 1839 | const struct stat *from_st, char const *to, | ||
1856 | 1840 | const struct stat *to_st, mode_t mode, bool backup) | ||
1857 | 1841 | { | ||
1858 | 1842 | if (from == NULL) | ||
1859 | 1843 | { | ||
1860 | 1844 | /* Remember which files should be deleted and only delete them when the | ||
1861 | 1845 | entire input to patch has been processed. This allows to correctly | ||
1862 | 1846 | determine for which files backup files have already been created. */ | ||
1863 | 1847 | |||
1864 | 1848 | delete_file_later (to, to_st, backup); | ||
1865 | 1849 | } | ||
1866 | 1850 | else if (pch_git_diff () && pch_says_nonexistent (reverse) != 2) | ||
1867 | 1851 | { | ||
1868 | 1852 | /* In git-style diffs, the "before" state of each patch refers to the initial | ||
1869 | 1853 | state before modifying any files, input files can be referenced more than | ||
1870 | 1854 | once (when creating copies), and output files are modified at most once. | ||
1871 | 1855 | However, the input to GNU patch may consist of multiple concatenated | ||
1872 | 1856 | git-style diffs, which must be processed separately. (The same output | ||
1873 | 1857 | file may go through multiple revisions.) | ||
1874 | 1858 | |||
1875 | 1859 | To implement this, we remember which files to /modify/ instead of | ||
1876 | 1860 | modifying the files immediately, but we create /new/ output files | ||
1877 | 1861 | immediately. The new output files serve as markers to detect when a | ||
1878 | 1862 | file is modified more than once; this allows to recognize most | ||
1879 | 1863 | concatenated git-style diffs. | ||
1880 | 1864 | */ | ||
1881 | 1865 | |||
1882 | 1866 | output_file_later (from, from_needs_removal, from_st, to, mode, backup); | ||
1883 | 1867 | } | ||
1884 | 1868 | else | ||
1885 | 1869 | output_file_now (from, from_needs_removal, from_st, to, mode, backup); | ||
1886 | 1870 | } | ||
1887 | 1871 | |||
1888 | 1872 | static void | ||
1889 | 1873 | dispose_file_to_output (const void *elt) | ||
1890 | 1874 | { | ||
1891 | 1875 | const struct file_to_output *file_to_output = elt; | ||
1892 | 1876 | |||
1893 | 1877 | free (file_to_output->from); | ||
1894 | 1878 | free (file_to_output->to); | ||
1895 | 1879 | } | ||
1896 | 1880 | |||
1897 | 1881 | static void | ||
1898 | 1882 | init_files_to_output (void) | ||
1899 | 1883 | { | ||
1900 | 1884 | files_to_output = gl_list_create_empty (GL_LINKED_LIST, NULL, NULL, | ||
1901 | 1885 | dispose_file_to_output, true); | ||
1902 | 1886 | } | ||
1903 | 1887 | |||
1904 | 1888 | static void | ||
1905 | 1889 | gl_list_clear (gl_list_t list) | ||
1906 | 1890 | { | ||
1907 | 1891 | while (gl_list_size (list) > 0) | ||
1908 | 1892 | gl_list_remove_at (list, 0); | ||
1909 | 1893 | } | ||
1910 | 1894 | |||
1911 | 1895 | static void | ||
1912 | 1896 | output_files (struct stat const *st) | ||
1913 | 1897 | { | ||
1914 | 1898 | gl_list_iterator_t iter; | ||
1915 | 1899 | const void *elt; | ||
1916 | 1900 | |||
1917 | 1901 | iter = gl_list_iterator (files_to_output); | ||
1918 | 1902 | while (gl_list_iterator_next (&iter, &elt, NULL)) | ||
1919 | 1903 | { | ||
1920 | 1904 | const struct file_to_output *file_to_output = elt; | ||
1921 | 1905 | bool from_needs_removal = true; | ||
1922 | 1906 | struct stat const *from_st = &file_to_output->from_st; | ||
1923 | 1907 | |||
1924 | 1908 | output_file_now (file_to_output->from, &from_needs_removal, | ||
1925 | 1909 | from_st, file_to_output->to, | ||
1926 | 1910 | file_to_output->mode, file_to_output->backup); | ||
1927 | 1911 | if (file_to_output->to && from_needs_removal) | ||
1928 | 1912 | unlink (file_to_output->from); | ||
1929 | 1913 | |||
1930 | 1914 | if (st && st->st_dev == from_st->st_dev && st->st_ino == from_st->st_ino) | ||
1931 | 1915 | { | ||
1932 | 1916 | /* Free the list up to here. */ | ||
1933 | 1917 | for (;;) | ||
1934 | 1918 | { | ||
1935 | 1919 | const void *elt2 = gl_list_get_at (files_to_output, 0); | ||
1936 | 1920 | gl_list_remove_at (files_to_output, 0); | ||
1937 | 1921 | if (elt == elt2) | ||
1938 | 1922 | break; | ||
1939 | 1923 | } | ||
1940 | 1924 | gl_list_iterator_free (&iter); | ||
1941 | 1925 | return; | ||
1942 | 1926 | } | ||
1943 | 1927 | } | ||
1944 | 1928 | gl_list_iterator_free (&iter); | ||
1945 | 1929 | gl_list_clear (files_to_output); | ||
1946 | 1930 | } | ||
1947 | 1931 | |||
1948 | 1932 | static void | ||
1949 | 1933 | forget_output_files (void) | ||
1950 | 1934 | { | ||
1951 | 1935 | gl_list_iterator_t iter = gl_list_iterator (files_to_output); | ||
1952 | 1936 | const void *elt; | ||
1953 | 1937 | |||
1954 | 1938 | while (gl_list_iterator_next (&iter, &elt, NULL)) | ||
1955 | 1939 | { | ||
1956 | 1940 | const struct file_to_output *file_to_output = elt; | ||
1957 | 1941 | |||
1958 | 1942 | unlink (file_to_output->from); | ||
1959 | 1943 | } | ||
1960 | 1944 | gl_list_iterator_free (&iter); | ||
1961 | 1945 | gl_list_clear (files_to_output); | ||
1962 | 1946 | } | ||
1963 | 1947 | |||
1964 | 1948 | /* Fatal exit with cleanup. */ | ||
1965 | 1949 | |||
1966 | 1950 | void | ||
1967 | 1951 | fatal_exit (int sig) | ||
1968 | 1952 | { | ||
1969 | 1953 | cleanup (); | ||
1970 | 1954 | |||
1971 | 1955 | if (sig) | ||
1972 | 1956 | exit_with_signal (sig); | ||
1973 | 1957 | |||
1974 | 1958 | exit (2); | ||
1975 | 1959 | } | ||
1976 | 1960 | |||
1977 | 1961 | static void | ||
1978 | 1962 | remove_if_needed (char const *name, bool *needs_removal) | ||
1979 | 1963 | { | ||
1980 | 1964 | if (*needs_removal) | ||
1981 | 1965 | { | ||
1982 | 1966 | unlink (name); | ||
1983 | 1967 | *needs_removal = false; | ||
1984 | 1968 | } | ||
1985 | 1969 | } | ||
1986 | 1970 | |||
1987 | 1971 | static void | ||
1988 | 1972 | cleanup (void) | ||
1989 | 1973 | { | ||
1990 | 1974 | remove_if_needed (TMPINNAME, &TMPINNAME_needs_removal); | ||
1991 | 1975 | remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal); | ||
1992 | 1976 | remove_if_needed (TMPPATNAME, &TMPPATNAME_needs_removal); | ||
1993 | 1977 | remove_if_needed (TMPREJNAME, &TMPREJNAME_needs_removal); | ||
1994 | 1978 | forget_output_files (); | ||
1995 | 1979 | } | ||
1996 | 0 | 1980 | ||
1997 | === modified file 'debian/changelog' | |||
1998 | --- debian/changelog 2013-11-04 12:36:11 +0000 | |||
1999 | +++ debian/changelog 2014-05-01 16:07:46 +0000 | |||
2000 | @@ -1,3 +1,10 @@ | |||
2001 | 1 | patch (2.7.1-4ubuntu1) UNRELEASED; urgency=medium | ||
2002 | 2 | |||
2003 | 3 | * debian/patches/fix-non-numeric-arg-crash.diff: Fix crash when option | ||
2004 | 4 | expecting a numeric given non-numeric (LP: #1306412). | ||
2005 | 5 | |||
2006 | 6 | -- James Hunt <james.hunt@ubuntu.com> Thu, 01 May 2014 17:00:17 +0100 | ||
2007 | 7 | |||
2008 | 1 | patch (2.7.1-4) unstable; urgency=low | 8 | patch (2.7.1-4) unstable; urgency=low |
2009 | 2 | 9 | ||
2010 | 3 | * New maintainer (closes: #728664). | 10 | * New maintainer (closes: #728664). |
2011 | 4 | 11 | ||
2012 | === added file 'debian/patches/fix-non-numeric-arg-crash.diff' | |||
2013 | --- debian/patches/fix-non-numeric-arg-crash.diff 1970-01-01 00:00:00 +0000 | |||
2014 | +++ debian/patches/fix-non-numeric-arg-crash.diff 2014-05-01 16:07:46 +0000 | |||
2015 | @@ -0,0 +1,19 @@ | |||
2016 | 1 | Description: Fix crash when an argument expecting a numeric is given | ||
2017 | 2 | a non-numeric. | ||
2018 | 3 | Author: James Hunt <james.hunt@ubuntu.com> | ||
2019 | 4 | Bug-Ubuntu: https://bugs.launchpad.net/bugs/1306412 | ||
2020 | 5 | Forwarded: yes | ||
2021 | 6 | Last-Update: 2014-05-01 | ||
2022 | 7 | |||
2023 | 8 | --- | ||
2024 | 9 | |||
2025 | 10 | --- a/src/patch.c | ||
2026 | 11 | +++ b/src/patch.c | ||
2027 | 12 | @@ -1975,5 +1975,6 @@ | ||
2028 | 13 | remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal); | ||
2029 | 14 | remove_if_needed (TMPPATNAME, &TMPPATNAME_needs_removal); | ||
2030 | 15 | remove_if_needed (TMPREJNAME, &TMPREJNAME_needs_removal); | ||
2031 | 16 | - forget_output_files (); | ||
2032 | 17 | + if (files_to_output) | ||
2033 | 18 | + forget_output_files (); | ||
2034 | 19 | } | ||
2035 | 0 | 20 | ||
2036 | === modified file 'debian/patches/series' | |||
2037 | --- debian/patches/series 2013-11-04 12:36:11 +0000 | |||
2038 | +++ debian/patches/series 2014-05-01 16:07:46 +0000 | |||
2039 | @@ -3,3 +3,4 @@ | |||
2040 | 3 | m-merge | 3 | m-merge |
2041 | 4 | #disable-update-version | 4 | #disable-update-version |
2042 | 5 | add_manpage_time.patch | 5 | add_manpage_time.patch |
2043 | 6 | fix-non-numeric-arg-crash.diff | ||
2044 | 6 | 7 | ||
2045 | === modified file 'src/patch.c' | |||
2046 | --- src/patch.c 2013-06-30 16:14:19 +0000 | |||
2047 | +++ src/patch.c 2014-05-01 16:07:46 +0000 | |||
2048 | @@ -1975,5 +1975,6 @@ | |||
2049 | 1975 | remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal); | 1975 | remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal); |
2050 | 1976 | remove_if_needed (TMPPATNAME, &TMPPATNAME_needs_removal); | 1976 | remove_if_needed (TMPPATNAME, &TMPPATNAME_needs_removal); |
2051 | 1977 | remove_if_needed (TMPREJNAME, &TMPREJNAME_needs_removal); | 1977 | remove_if_needed (TMPREJNAME, &TMPREJNAME_needs_removal); |
2053 | 1978 | forget_output_files (); | 1978 | if (files_to_output) |
2054 | 1979 | forget_output_files (); | ||
2055 | 1979 | } | 1980 | } |
Ah - I see debian has now applied the original patch so maybe easier to sync from there?