diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-04-14 16:05:26 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-04-14 16:05:26 +0200 |
commit | 75568354f6e2ab08302085bbcb32c3368c49b86f (patch) | |
tree | d314a3475bbeb5b4edc9e0fa27ac848af968ff07 | |
parent | d5f5045b43bd7a55402dfcecde511a2c207d07b7 (diff) | |
download | busybox-w32-75568354f6e2ab08302085bbcb32c3368c49b86f.tar.gz busybox-w32-75568354f6e2ab08302085bbcb32c3368c49b86f.tar.bz2 busybox-w32-75568354f6e2ab08302085bbcb32c3368c49b86f.zip |
patch: implement --dry-run
function old new delta
static.patch_longopts - 137 +137
patch_main 2053 2135 +82
fail_hunk 132 139 +7
finish_oldfile 119 124 +5
packed_usage 32807 32787 -20
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 3/1 up/down: 231/-20) Total: 211 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | editors/patch.c | 129 |
1 files changed, 86 insertions, 43 deletions
diff --git a/editors/patch.c b/editors/patch.c index a51b7a502..eca6bc5f6 100644 --- a/editors/patch.c +++ b/editors/patch.c | |||
@@ -15,7 +15,6 @@ | |||
15 | * -D define wrap #ifdef and #ifndef around changes | 15 | * -D define wrap #ifdef and #ifndef around changes |
16 | * -o outfile output here instead of in place | 16 | * -o outfile output here instead of in place |
17 | * -r rejectfile write rejected hunks to this file | 17 | * -r rejectfile write rejected hunks to this file |
18 | * --dry-run (regression!) | ||
19 | * | 18 | * |
20 | * -f force (no questions asked) | 19 | * -f force (no questions asked) |
21 | * -F fuzz (number, default 2) | 20 | * -F fuzz (number, default 2) |
@@ -34,23 +33,15 @@ | |||
34 | //usage:#define patch_trivial_usage | 33 | //usage:#define patch_trivial_usage |
35 | //usage: "[OPTIONS] [ORIGFILE [PATCHFILE]]" | 34 | //usage: "[OPTIONS] [ORIGFILE [PATCHFILE]]" |
36 | //usage:#define patch_full_usage "\n\n" | 35 | //usage:#define patch_full_usage "\n\n" |
37 | //usage: IF_LONG_OPTS( | ||
38 | //usage: " -p,--strip N Strip N leading components from file names" | ||
39 | //usage: "\n -i,--input DIFF Read DIFF instead of stdin" | ||
40 | //usage: "\n -R,--reverse Reverse patch" | ||
41 | //usage: "\n -N,--forward Ignore already applied patches" | ||
42 | /*usage: "\n --dry-run Don't actually change files" - TODO */ | ||
43 | //usage: "\n -E,--remove-empty-files Remove output files if they become empty" | ||
44 | //usage: ) | ||
45 | //usage: IF_NOT_LONG_OPTS( | ||
46 | //usage: " -p N Strip N leading components from file names" | 36 | //usage: " -p N Strip N leading components from file names" |
47 | //usage: "\n -i DIFF Read DIFF instead of stdin" | 37 | //usage: "\n -i DIFF Read DIFF instead of stdin" |
48 | //usage: "\n -R Reverse patch" | 38 | //usage: "\n -R Reverse patch" |
49 | //usage: "\n -N Ignore already applied patches" | 39 | //usage: "\n -N Ignore already applied patches" |
50 | //usage: "\n -E Remove output files if they become empty" | 40 | //usage: "\n -E Remove output files if they become empty" |
41 | //usage: IF_LONG_OPTS( | ||
42 | //usage: "\n --dry-run Don't actually change files" | ||
51 | //usage: ) | 43 | //usage: ) |
52 | /* -u "interpret as unified diff" is supported but not documented: this info is not useful for --help */ | 44 | /* -u "interpret as unified diff" is supported but not documented: this info is not useful for --help */ |
53 | /* -x "debug" is supported but does nothing */ | ||
54 | //usage: | 45 | //usage: |
55 | //usage:#define patch_example_usage | 46 | //usage:#define patch_example_usage |
56 | //usage: "$ patch -p1 < example.diff\n" | 47 | //usage: "$ patch -p1 < example.diff\n" |
@@ -58,6 +49,7 @@ | |||
58 | 49 | ||
59 | #include "libbb.h" | 50 | #include "libbb.h" |
60 | 51 | ||
52 | #define PATCH_DEBUG 0 | ||
61 | 53 | ||
62 | // libbb candidate? | 54 | // libbb candidate? |
63 | 55 | ||
@@ -122,16 +114,18 @@ struct globals { | |||
122 | } while (0) | 114 | } while (0) |
123 | 115 | ||
124 | 116 | ||
125 | #define FLAG_STR "Rup:i:NEx" | 117 | #define FLAG_STR "Rup:i:NEfg" |
126 | /* FLAG_REVERSE must be == 1! Code uses this fact. */ | 118 | /* FLAG_REVERSE must be == 1! Code uses this fact. */ |
127 | #define FLAG_REVERSE (1 << 0) | 119 | #define FLAG_REVERSE (1 << 0) |
128 | #define FLAG_u (1 << 1) | 120 | #define FLAG_u (1 << 1) |
129 | #define FLAG_PATHLEN (1 << 2) | 121 | #define FLAG_PATHLEN (1 << 2) |
130 | #define FLAG_INPUT (1 << 3) | 122 | #define FLAG_INPUT (1 << 3) |
131 | #define FLAG_IGNORE (1 << 4) | 123 | #define FLAG_IGNORE (1 << 4) |
132 | #define FLAG_RMEMPTY (1 << 5) | 124 | #define FLAG_RMEMPTY (1 << 5) |
133 | /* Enable this bit and use -x for debug output: */ | 125 | #define FLAG_f_unused (1 << 6) |
134 | #define FLAG_DEBUG (0 << 6) | 126 | #define FLAG_g_unused (1 << 7) |
127 | #define FLAG_dry_run ((1 << 8) * ENABLE_LONG_OPTS) | ||
128 | |||
135 | 129 | ||
136 | // Dispose of a line of input, either by writing it out or discarding it. | 130 | // Dispose of a line of input, either by writing it out or discarding it. |
137 | 131 | ||
@@ -140,8 +134,6 @@ struct globals { | |||
140 | // state = 3: write whole line to fileout | 134 | // state = 3: write whole line to fileout |
141 | // state > 3: write line+1 to fileout when *line != state | 135 | // state > 3: write line+1 to fileout when *line != state |
142 | 136 | ||
143 | #define PATCH_DEBUG (option_mask32 & FLAG_DEBUG) | ||
144 | |||
145 | static void do_line(void *data) | 137 | static void do_line(void *data) |
146 | { | 138 | { |
147 | struct double_list *dlist = data; | 139 | struct double_list *dlist = data; |
@@ -168,12 +160,14 @@ static void finish_oldfile(void) | |||
168 | } | 160 | } |
169 | xclose(TT.fileout); | 161 | xclose(TT.fileout); |
170 | 162 | ||
171 | temp = xstrdup(TT.tempname); | 163 | if (!ENABLE_LONG_OPTS || TT.tempname[0]) { /* not --dry-run? */ |
172 | temp[strlen(temp) - 6] = '\0'; | 164 | temp = xstrdup(TT.tempname); |
173 | rename(TT.tempname, temp); | 165 | temp[strlen(temp) - 6] = '\0'; |
174 | free(temp); | 166 | rename(TT.tempname, temp); |
167 | free(temp); | ||
168 | free(TT.tempname); | ||
169 | } | ||
175 | 170 | ||
176 | free(TT.tempname); | ||
177 | TT.tempname = NULL; | 171 | TT.tempname = NULL; |
178 | } | 172 | } |
179 | TT.fileout = TT.filein = -1; | 173 | TT.fileout = TT.filein = -1; |
@@ -197,8 +191,10 @@ static void fail_hunk(void) | |||
197 | // Abort the copy and delete the temporary file. | 191 | // Abort the copy and delete the temporary file. |
198 | close(TT.filein); | 192 | close(TT.filein); |
199 | close(TT.fileout); | 193 | close(TT.fileout); |
200 | unlink(TT.tempname); | 194 | if (!ENABLE_LONG_OPTS || TT.tempname[0]) { /* not --dry-run? */ |
201 | free(TT.tempname); | 195 | unlink(TT.tempname); |
196 | free(TT.tempname); | ||
197 | } | ||
202 | TT.tempname = NULL; | 198 | TT.tempname = NULL; |
203 | 199 | ||
204 | TT.state = 0; | 200 | TT.state = 0; |
@@ -239,6 +235,7 @@ static int apply_one_hunk(void) | |||
239 | plist = TT.current_hunk; | 235 | plist = TT.current_hunk; |
240 | buf = NULL; | 236 | buf = NULL; |
241 | if (reverse ? TT.oldlen : TT.newlen) for (;;) { | 237 | if (reverse ? TT.oldlen : TT.newlen) for (;;) { |
238 | //FIXME: this performs 1-byte reads: | ||
242 | char *data = xmalloc_reads(TT.filein, NULL); | 239 | char *data = xmalloc_reads(TT.filein, NULL); |
243 | 240 | ||
244 | TT.linenum++; | 241 | TT.linenum++; |
@@ -369,9 +366,45 @@ int patch_main(int argc UNUSED_PARAM, char **argv) | |||
369 | long oldlen = oldlen; /* for compiler */ | 366 | long oldlen = oldlen; /* for compiler */ |
370 | long newlen = newlen; /* for compiler */ | 367 | long newlen = newlen; /* for compiler */ |
371 | 368 | ||
369 | #if ENABLE_LONG_OPTS | ||
370 | static const char patch_longopts[] ALIGN1 = | ||
371 | "reverse\0" No_argument "R" | ||
372 | "unified\0" No_argument "u" | ||
373 | "strip\0" Required_argument "p" | ||
374 | "input\0" Required_argument "i" | ||
375 | "forward\0" No_argument "N" | ||
376 | # if ENABLE_DESKTOP | ||
377 | "remove-empty-files\0" No_argument "E" /*ignored*/ | ||
378 | /* "debug" Required_argument "x" */ | ||
379 | # endif | ||
380 | /* "Assume user knows what [s]he is doing, do not ask any questions": */ | ||
381 | "force\0" No_argument "f" /*ignored*/ | ||
382 | # if ENABLE_DESKTOP | ||
383 | /* "Controls actions when a file is under RCS or SCCS control, | ||
384 | * and does not exist or is read-only and matches the default version, | ||
385 | * or when a file is under ClearCase control and does not exist..." | ||
386 | * IOW: rather obscure option. | ||
387 | * But Gentoo's portage does use -g0 | ||
388 | */ | ||
389 | "get\0" Required_argument "g" /*ignored*/ | ||
390 | # endif | ||
391 | "dry-run\0" No_argument "\xfd" | ||
392 | # if ENABLE_DESKTOP | ||
393 | "backup-if-mismatch\0" No_argument "\xfe" /*ignored*/ | ||
394 | "no-backup-if-mismatch\0" No_argument "\xff" /*ignored*/ | ||
395 | # endif | ||
396 | ; | ||
397 | #endif | ||
398 | |||
372 | INIT_TT(); | 399 | INIT_TT(); |
373 | 400 | ||
401 | #if ENABLE_LONG_OPTS | ||
402 | opts = getopt32long(argv, FLAG_STR, patch_longopts, &opt_p, &opt_i); | ||
403 | #else | ||
374 | opts = getopt32(argv, FLAG_STR, &opt_p, &opt_i); | 404 | opts = getopt32(argv, FLAG_STR, &opt_p, &opt_i); |
405 | #endif | ||
406 | //bb_error_msg_and_die("opts:%x", opts); | ||
407 | |||
375 | argv += optind; | 408 | argv += optind; |
376 | reverse = opts & FLAG_REVERSE; | 409 | reverse = opts & FLAG_REVERSE; |
377 | TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! | 410 | TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! |
@@ -517,10 +550,12 @@ int patch_main(int argc UNUSED_PARAM, char **argv) | |||
517 | if (option_mask32 & FLAG_RMEMPTY) { | 550 | if (option_mask32 & FLAG_RMEMPTY) { |
518 | // If flag -E or --remove-empty-files is set | 551 | // If flag -E or --remove-empty-files is set |
519 | printf("removing %s\n", name); | 552 | printf("removing %s\n", name); |
520 | xunlink(name); | 553 | if (!(opts & FLAG_dry_run)) |
554 | xunlink(name); | ||
521 | } else { | 555 | } else { |
522 | printf("patching file %s\n", name); | 556 | printf("patching file %s\n", name); |
523 | xclose(xopen(name, O_WRONLY | O_TRUNC)); | 557 | if (!(opts & FLAG_dry_run)) |
558 | xclose(xopen(name, O_WRONLY | O_TRUNC)); | ||
524 | } | 559 | } |
525 | // If we've got a file to open, do so. | 560 | // If we've got a file to open, do so. |
526 | } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { | 561 | } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { |
@@ -529,24 +564,32 @@ int patch_main(int argc UNUSED_PARAM, char **argv) | |||
529 | // If the old file was null, we're creating a new one. | 564 | // If the old file was null, we're creating a new one. |
530 | if (strcmp(oldname, "/dev/null") == 0 || !oldsum) { | 565 | if (strcmp(oldname, "/dev/null") == 0 || !oldsum) { |
531 | printf("creating %s\n", name); | 566 | printf("creating %s\n", name); |
532 | s = strrchr(name, '/'); | 567 | if (!(opts & FLAG_dry_run)) { |
533 | if (s) { | 568 | s = strrchr(name, '/'); |
534 | *s = 0; | 569 | if (s) { |
535 | bb_make_directory(name, -1, FILEUTILS_RECUR); | 570 | *s = '\0'; |
536 | *s = '/'; | 571 | bb_make_directory(name, -1, FILEUTILS_RECUR); |
572 | *s = '/'; | ||
573 | } | ||
574 | TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); | ||
575 | } else { | ||
576 | TT.filein = xopen("/dev/null", O_RDONLY); | ||
537 | } | 577 | } |
538 | TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); | ||
539 | } else { | 578 | } else { |
540 | printf("patching file %s\n", name); | 579 | printf("patching file %s\n", name); |
541 | TT.filein = xopen(name, O_RDONLY); | 580 | TT.filein = xopen(name, O_RDONLY); |
542 | } | 581 | } |
543 | 582 | ||
544 | TT.tempname = xasprintf("%sXXXXXX", name); | 583 | if (!(opts & FLAG_dry_run)) { |
545 | TT.fileout = xmkstemp(TT.tempname); | 584 | TT.tempname = xasprintf("%sXXXXXX", name); |
546 | // Set permissions of output file | 585 | TT.fileout = xmkstemp(TT.tempname); |
547 | fstat(TT.filein, &statbuf); | 586 | // Set permissions of output file |
548 | fchmod(TT.fileout, statbuf.st_mode); | 587 | fstat(TT.filein, &statbuf); |
549 | 588 | fchmod(TT.fileout, statbuf.st_mode); | |
589 | } else { | ||
590 | TT.tempname = (char*)""; | ||
591 | TT.fileout = xopen("/dev/null", O_WRONLY); | ||
592 | } | ||
550 | TT.linenum = 0; | 593 | TT.linenum = 0; |
551 | TT.hunknum = 0; | 594 | TT.hunknum = 0; |
552 | } | 595 | } |