From 75568354f6e2ab08302085bbcb32c3368c49b86f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 14 Apr 2018 16:05:26 +0200 Subject: [PATCH] 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 --- editors/patch.c | 129 ++++++++++++++++++++++++++++++++---------------- 1 file 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 @@ * -D define wrap #ifdef and #ifndef around changes * -o outfile output here instead of in place * -r rejectfile write rejected hunks to this file - * --dry-run (regression!) * * -f force (no questions asked) * -F fuzz (number, default 2) @@ -34,23 +33,15 @@ //usage:#define patch_trivial_usage //usage: "[OPTIONS] [ORIGFILE [PATCHFILE]]" //usage:#define patch_full_usage "\n\n" -//usage: IF_LONG_OPTS( -//usage: " -p,--strip N Strip N leading components from file names" -//usage: "\n -i,--input DIFF Read DIFF instead of stdin" -//usage: "\n -R,--reverse Reverse patch" -//usage: "\n -N,--forward Ignore already applied patches" -/*usage: "\n --dry-run Don't actually change files" - TODO */ -//usage: "\n -E,--remove-empty-files Remove output files if they become empty" -//usage: ) -//usage: IF_NOT_LONG_OPTS( //usage: " -p N Strip N leading components from file names" //usage: "\n -i DIFF Read DIFF instead of stdin" //usage: "\n -R Reverse patch" //usage: "\n -N Ignore already applied patches" //usage: "\n -E Remove output files if they become empty" +//usage: IF_LONG_OPTS( +//usage: "\n --dry-run Don't actually change files" //usage: ) /* -u "interpret as unified diff" is supported but not documented: this info is not useful for --help */ -/* -x "debug" is supported but does nothing */ //usage: //usage:#define patch_example_usage //usage: "$ patch -p1 < example.diff\n" @@ -58,6 +49,7 @@ #include "libbb.h" +#define PATCH_DEBUG 0 // libbb candidate? @@ -122,16 +114,18 @@ struct globals { } while (0) -#define FLAG_STR "Rup:i:NEx" +#define FLAG_STR "Rup:i:NEfg" /* FLAG_REVERSE must be == 1! Code uses this fact. */ -#define FLAG_REVERSE (1 << 0) -#define FLAG_u (1 << 1) -#define FLAG_PATHLEN (1 << 2) -#define FLAG_INPUT (1 << 3) -#define FLAG_IGNORE (1 << 4) -#define FLAG_RMEMPTY (1 << 5) -/* Enable this bit and use -x for debug output: */ -#define FLAG_DEBUG (0 << 6) +#define FLAG_REVERSE (1 << 0) +#define FLAG_u (1 << 1) +#define FLAG_PATHLEN (1 << 2) +#define FLAG_INPUT (1 << 3) +#define FLAG_IGNORE (1 << 4) +#define FLAG_RMEMPTY (1 << 5) +#define FLAG_f_unused (1 << 6) +#define FLAG_g_unused (1 << 7) +#define FLAG_dry_run ((1 << 8) * ENABLE_LONG_OPTS) + // Dispose of a line of input, either by writing it out or discarding it. @@ -140,8 +134,6 @@ struct globals { // state = 3: write whole line to fileout // state > 3: write line+1 to fileout when *line != state -#define PATCH_DEBUG (option_mask32 & FLAG_DEBUG) - static void do_line(void *data) { struct double_list *dlist = data; @@ -168,12 +160,14 @@ static void finish_oldfile(void) } xclose(TT.fileout); - temp = xstrdup(TT.tempname); - temp[strlen(temp) - 6] = '\0'; - rename(TT.tempname, temp); - free(temp); + if (!ENABLE_LONG_OPTS || TT.tempname[0]) { /* not --dry-run? */ + temp = xstrdup(TT.tempname); + temp[strlen(temp) - 6] = '\0'; + rename(TT.tempname, temp); + free(temp); + free(TT.tempname); + } - free(TT.tempname); TT.tempname = NULL; } TT.fileout = TT.filein = -1; @@ -197,8 +191,10 @@ static void fail_hunk(void) // Abort the copy and delete the temporary file. close(TT.filein); close(TT.fileout); - unlink(TT.tempname); - free(TT.tempname); + if (!ENABLE_LONG_OPTS || TT.tempname[0]) { /* not --dry-run? */ + unlink(TT.tempname); + free(TT.tempname); + } TT.tempname = NULL; TT.state = 0; @@ -239,6 +235,7 @@ static int apply_one_hunk(void) plist = TT.current_hunk; buf = NULL; if (reverse ? TT.oldlen : TT.newlen) for (;;) { +//FIXME: this performs 1-byte reads: char *data = xmalloc_reads(TT.filein, NULL); TT.linenum++; @@ -369,9 +366,45 @@ int patch_main(int argc UNUSED_PARAM, char **argv) long oldlen = oldlen; /* for compiler */ long newlen = newlen; /* for compiler */ +#if ENABLE_LONG_OPTS + static const char patch_longopts[] ALIGN1 = + "reverse\0" No_argument "R" + "unified\0" No_argument "u" + "strip\0" Required_argument "p" + "input\0" Required_argument "i" + "forward\0" No_argument "N" +# if ENABLE_DESKTOP + "remove-empty-files\0" No_argument "E" /*ignored*/ + /* "debug" Required_argument "x" */ +# endif + /* "Assume user knows what [s]he is doing, do not ask any questions": */ + "force\0" No_argument "f" /*ignored*/ +# if ENABLE_DESKTOP + /* "Controls actions when a file is under RCS or SCCS control, + * and does not exist or is read-only and matches the default version, + * or when a file is under ClearCase control and does not exist..." + * IOW: rather obscure option. + * But Gentoo's portage does use -g0 + */ + "get\0" Required_argument "g" /*ignored*/ +# endif + "dry-run\0" No_argument "\xfd" +# if ENABLE_DESKTOP + "backup-if-mismatch\0" No_argument "\xfe" /*ignored*/ + "no-backup-if-mismatch\0" No_argument "\xff" /*ignored*/ +# endif + ; +#endif + INIT_TT(); +#if ENABLE_LONG_OPTS + opts = getopt32long(argv, FLAG_STR, patch_longopts, &opt_p, &opt_i); +#else opts = getopt32(argv, FLAG_STR, &opt_p, &opt_i); +#endif + //bb_error_msg_and_die("opts:%x", opts); + argv += optind; reverse = opts & FLAG_REVERSE; 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) if (option_mask32 & FLAG_RMEMPTY) { // If flag -E or --remove-empty-files is set printf("removing %s\n", name); - xunlink(name); + if (!(opts & FLAG_dry_run)) + xunlink(name); } else { printf("patching file %s\n", name); - xclose(xopen(name, O_WRONLY | O_TRUNC)); + if (!(opts & FLAG_dry_run)) + xclose(xopen(name, O_WRONLY | O_TRUNC)); } // If we've got a file to open, do so. } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { @@ -529,24 +564,32 @@ int patch_main(int argc UNUSED_PARAM, char **argv) // If the old file was null, we're creating a new one. if (strcmp(oldname, "/dev/null") == 0 || !oldsum) { printf("creating %s\n", name); - s = strrchr(name, '/'); - if (s) { - *s = 0; - bb_make_directory(name, -1, FILEUTILS_RECUR); - *s = '/'; + if (!(opts & FLAG_dry_run)) { + s = strrchr(name, '/'); + if (s) { + *s = '\0'; + bb_make_directory(name, -1, FILEUTILS_RECUR); + *s = '/'; + } + TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); + } else { + TT.filein = xopen("/dev/null", O_RDONLY); } - TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); } else { printf("patching file %s\n", name); TT.filein = xopen(name, O_RDONLY); } - TT.tempname = xasprintf("%sXXXXXX", name); - TT.fileout = xmkstemp(TT.tempname); - // Set permissions of output file - fstat(TT.filein, &statbuf); - fchmod(TT.fileout, statbuf.st_mode); - + if (!(opts & FLAG_dry_run)) { + TT.tempname = xasprintf("%sXXXXXX", name); + TT.fileout = xmkstemp(TT.tempname); + // Set permissions of output file + fstat(TT.filein, &statbuf); + fchmod(TT.fileout, statbuf.st_mode); + } else { + TT.tempname = (char*)""; + TT.fileout = xopen("/dev/null", O_WRONLY); + } TT.linenum = 0; TT.hunknum = 0; } -- 2.25.1