diff --git a/editors/patch.c b/editors/patch.c index 4a9715144..580ee147c 100644 --- a/editors/patch.c +++ b/editors/patch.c @@ -78,12 +78,23 @@ int patch_main(int argc UNUSED_PARAM, char **argv) enum { OPT_R = (1 << 2), OPT_N = (1 << 3), + OPT_dry_run = (1 << 4) * ENABLE_LONG_OPTS, }; xfunc_error_retval = 2; { const char *p = "-1"; const char *i = "-"; /* compat */ +#if ENABLE_LONG_OPTS + static const char patch_longopts[] ALIGN1 = + "strip\0" Required_argument "p" + "input\0" Required_argument "i" + "reverse\0" No_argument "R" + "forward\0" No_argument "N" + "dry-run\0" No_argument "\xff" + ; + applet_long_options = patch_longopts; +#endif opt = getopt32(argv, "p:i:RN", &p, &i); if (opt & OPT_R) plus = '-'; @@ -97,7 +108,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv) FILE *dst_stream; //char *old_filename; char *new_filename; - char *backup_filename; + char *backup_filename = NULL; unsigned src_cur_line = 1; unsigned dst_cur_line = 0; unsigned dst_beg_line; @@ -131,16 +142,21 @@ int patch_main(int argc UNUSED_PARAM, char **argv) bb_make_directory(new_filename, -1, FILEUTILS_RECUR); *slash = '/'; } - backup_filename = NULL; src_stream = NULL; saved_stat.st_mode = 0644; - } else { + } else if (!(opt & OPT_dry_run)) { backup_filename = xasprintf("%s.orig", new_filename); xrename(new_filename, backup_filename); src_stream = xfopen_for_read(backup_filename); + } else + src_stream = xfopen_for_read(new_filename); + + if (opt & OPT_dry_run) { + dst_stream = xfopen_for_write("/dev/null"); + } else { + dst_stream = xfopen_for_write(new_filename); + fchmod(fileno(dst_stream), saved_stat.st_mode); } - dst_stream = xfopen_for_write(new_filename); - fchmod(fileno(dst_stream), saved_stat.st_mode); printf("patching file %s\n", new_filename); @@ -189,6 +205,11 @@ int patch_main(int argc UNUSED_PARAM, char **argv) patch_line = xmalloc_fgets(patch_file); if (patch_line == NULL) break; /* EOF */ + if (!*patch_line) { + /* whitespace-damaged patch with "" lines */ + free(patch_line); + patch_line = xstrdup(" "); + } if ((*patch_line != '-') && (*patch_line != '+') && (*patch_line != ' ') ) { @@ -244,7 +265,9 @@ int patch_main(int argc UNUSED_PARAM, char **argv) if (backup_filename) { unlink(backup_filename); } - if ((dst_cur_line == 0) || (dst_beg_line == 0)) { + if (!(opt & OPT_dry_run) + && ((dst_cur_line == 0) || (dst_beg_line == 0)) + ) { /* The new patched file is empty, remove it */ xunlink(new_filename); // /* old_filename and new_filename may be the same file */ diff --git a/include/usage.h b/include/usage.h index d03ec2295..85561c558 100644 --- a/include/usage.h +++ b/include/usage.h @@ -898,7 +898,7 @@ "\n -d Daemonize" \ #define dos2unix_trivial_usage \ - "[OPTION] [FILE]" + "[OPTIONS] [FILE]" #define dos2unix_full_usage "\n\n" \ "Convert FILE in-place from DOS to Unix format.\n" \ "When no file is given, use stdin/stdout.\n" \ @@ -907,7 +907,7 @@ "\n -d unix2dos" \ #define unix2dos_trivial_usage \ - "[OPTION] [FILE]" + "[OPTIONS] [FILE]" #define unix2dos_full_usage "\n\n" \ "Convert FILE in-place from Unix to DOS format.\n" \ "When no file is given, use stdin/stdout.\n" \ @@ -3250,12 +3250,21 @@ ) #define patch_trivial_usage \ - "[-p NUM] [-i DIFF] [-R] [-N]" + "[OPTIONS] [ORIGFILE [PATCHFILE]]" #define patch_full_usage "\n\n" \ + IF_LONG_OPTS( \ + " -p,--strip NUM Strip NUM leading components from file names" \ + "\n -i,--input DIFF Read DIFF instead of stdin" \ + "\n -R,--reverse Reverse patch" \ + "\n -N,--forward Ignore already applied patches" \ + "\n --dry-run Don't actually change files" \ + ) \ + IF_NOT_LONG_OPTS( \ " -p NUM Strip NUM leading components from file names" \ "\n -i DIFF Read DIFF instead of stdin" \ "\n -R Reverse patch" \ "\n -N Ignore already applied patches" \ + ) #define patch_example_usage \ "$ patch -p1 < example.diff\n" \ diff --git a/testsuite/patch.tests b/testsuite/patch.tests index cfe69b76a..178048d2a 100755 --- a/testsuite/patch.tests +++ b/testsuite/patch.tests @@ -7,7 +7,7 @@ # testing "test name" "options" "expected result" "file input" "stdin" testing "patch with old_file == new_file" \ - "patch; echo $?; cat input" \ + 'patch; echo $?; cat input' \ "\ patching file input 0 @@ -15,7 +15,10 @@ qwe asd zxc " \ - "qwe\nzxc\n" \ +"\ +qwe +zxc +" \ "\ --- input Jan 01 01:01:01 2000 +++ input Jan 01 01:01:01 2000 @@ -26,7 +29,7 @@ zxc " \ testing "patch with nonexistent old_file" \ - "patch; echo $?; cat input" \ + 'patch; echo $?; cat input' \ "\ patching file input 0 @@ -34,7 +37,10 @@ qwe asd zxc " \ - "qwe\nzxc\n" \ +"\ +qwe +zxc +" \ "\ --- input.doesnt_exist Jan 01 01:01:01 2000 +++ input Jan 01 01:01:01 2000 @@ -45,14 +51,18 @@ zxc " \ testing "patch -R with nonexistent old_file" \ - "patch -R; echo $?; cat input" \ + 'patch -R; echo $?; cat input' \ "\ patching file input 0 qwe zxc " \ - "qwe\nasd\nzxc\n" \ +"\ +qwe +asd +zxc +" \ "\ --- input.doesnt_exist Jan 01 01:01:01 2000 +++ input Jan 01 01:01:01 2000 @@ -62,4 +72,29 @@ zxc zxc " \ +testing "patch detects already applied hunk" \ + 'patch 2>&1; echo $?; cat input' \ +"\ +patching file input +patch: hunk #1 FAILED at 1 +patch: 1 out of 1 hunk FAILED +1 +abc +def +123 +" \ +"\ +abc +def +123 +" \ +"\ +--- input.old Jan 01 01:01:01 2000 ++++ input Jan 01 01:01:01 2000 +@@ -1,2 +1,3 @@ + abc ++def + 123 +" \ + exit $FAILCOUNT