traceroute: fix help text to not show -6 when traceroute6 is off
[oweals/busybox.git] / editors / patch.c
index 6f42b835c0074ebeb0f7475a83487d942b5cd81c..580ee147c2e02ac3bcb2458ed6a68390a2e37d1f 100644 (file)
@@ -50,7 +50,7 @@ static char *extract_filename(char *line, int patch_level, const char *pat)
 
        if (strncmp(line, pat, 4) == 0) {
                /* Terminate string at end of source filename */
-               line[strcspn(line,"\t\n\r")] = '\0';
+               line[strcspn(line, "\t\n\r")] = '\0';
 
                /* Skip over (patch_level) number of leading directories */
                while (patch_level--) {
@@ -66,7 +66,7 @@ static char *extract_filename(char *line, int patch_level, const char *pat)
 }
 
 int patch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
+int patch_main(int argc UNUSED_PARAM, char **argv)
 {
        struct stat saved_stat;
        char *patch_line;
@@ -74,24 +74,41 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
        int patch_level;
        int ret = 0;
        char plus = '+';
+       unsigned opt;
+       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 (getopt32(argv, "p:i:R", &p, &i) & 4)
+#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 = '-';
                patch_level = xatoi(p); /* can be negative! */
                patch_file = xfopen_stdin(i);
        }
 
-       patch_line = xmalloc_getline(patch_file);
+       patch_line = xmalloc_fgetline(patch_file);
        while (patch_line) {
                FILE *src_stream;
                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;
@@ -106,7 +123,7 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
                        /* Extract the filename used before the patch was generated */
                        new_filename = extract_filename(patch_line, patch_level, "--- ");
                        // was old_filename above
-                       patch_line = xmalloc_getline(patch_file);
+                       patch_line = xmalloc_fgetline(patch_file);
                        if (!patch_line) goto quit;
                } while (!new_filename);
                free(new_filename); // "source" filename is irrelevant
@@ -125,16 +142,21 @@ int patch_main(int argc ATTRIBUTE_UNUSED, 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(backup_filename, "r");
+                       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(new_filename, "w");
-               fchmod(fileno(dst_stream), saved_stat.st_mode);
 
                printf("patching file %s\n", new_filename);
 
@@ -183,6 +205,11 @@ int patch_main(int argc ATTRIBUTE_UNUSED, 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 != ' ')
                                ) {
@@ -202,6 +229,10 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv)
                                                                src_line = NULL;
                                                }
                                        }
+                                       /* Do not patch an already patched hunk with -N */
+                                       if (src_line == 0 && (opt & OPT_N)) {
+                                               continue;
+                                       }
                                        if (!src_line) {
                                                bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start);
                                                bad_hunk_count++;
@@ -234,7 +265,9 @@ int patch_main(int argc ATTRIBUTE_UNUSED, 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 */