aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-04-14 16:05:26 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-04-14 16:05:26 +0200
commit75568354f6e2ab08302085bbcb32c3368c49b86f (patch)
treed314a3475bbeb5b4edc9e0fa27ac848af968ff07
parentd5f5045b43bd7a55402dfcecde511a2c207d07b7 (diff)
downloadbusybox-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.c129
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
145static void do_line(void *data) 137static 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 }