ntpd: default to FEATURE_NTP_AUTH=y
[oweals/busybox.git] / editors / diff.c
index b08ded3a157d47a1559d33339309faae62233ca2..1462a9b18656372cd102882641a93a6666273e57 100644 (file)
@@ -12,7 +12,6 @@
  *
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
-
 /*
  * The following code uses an algorithm due to Harold Stone,
  * which finds a pair of longest identical subsequences in
  * 3*(number of k-candidates installed), typically about
  * 6n words for files of length n.
  */
+//config:config DIFF
+//config:      bool "diff (13 kb)"
+//config:      default y
+//config:      help
+//config:      diff compares two files or directories and outputs the
+//config:      differences between them in a form that can be given to
+//config:      the patch command.
+//config:
+//config:config FEATURE_DIFF_LONG_OPTIONS
+//config:      bool "Enable long options"
+//config:      default y
+//config:      depends on DIFF && LONG_OPTS
+//config:
+//config:config FEATURE_DIFF_DIR
+//config:      bool "Enable directory support"
+//config:      default y
+//config:      depends on DIFF
+//config:      help
+//config:      This option enables support for directory and subdirectory
+//config:      comparison.
+
+//applet:IF_DIFF(APPLET(diff, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_DIFF) += diff.o
 
 //usage:#define diff_trivial_usage
 //usage:       "[-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2"
 //usage:     "\n       -w      Ignore all whitespace"
 
 #include "libbb.h"
+#include "common_bufsiz.h"
 
 #if 0
 # define dbg_error_msg(...) bb_error_msg(__VA_ARGS__)
@@ -269,17 +293,6 @@ static int search(const int *c, int k, int y, const struct cand *list)
        }
 }
 
-static unsigned isqrt(unsigned n)
-{
-       unsigned x = 1;
-       while (1) {
-               const unsigned y = x;
-               x = ((n / x) + x) >> 1;
-               if (x <= (y + 1) && x >= (y - 1))
-                       return x;
-       }
-}
-
 static void stone(const int *a, int n, const int *b, int *J, int pref)
 {
        const unsigned isq = isqrt(n);
@@ -336,7 +349,7 @@ static void stone(const int *a, int n, const int *b, int *J, int pref)
 }
 
 struct line {
-       /* 'serial' is not used in the begining, so we reuse it
+       /* 'serial' is not used in the beginning, so we reuse it
         * to store line offsets, thus reducing memory pressure
         */
        union {
@@ -406,7 +419,7 @@ static void fetch(FILE_and_pos_t *ft, const off_t *ix, int a, int b, int ch)
                for (j = 0, col = 0; j < ix[i] - ix[i - 1]; j++) {
                        int c = fgetc(ft->ft_fp);
                        if (c == EOF) {
-                               printf("\n\\ No newline at end of file\n");
+                               puts("\n\\ No newline at end of file");
                                return;
                        }
                        ft->ft_pos++;
@@ -631,8 +644,8 @@ static bool diff(FILE* fp[2], char *file[2])
                                }
 
                                for (j = 0; j < 2; j++)
-                                       for (k = v[j].a; k < v[j].b; k++)
-                                               nonempty |= (ix[j][k+1] - ix[j][k] != 1);
+                                       for (k = v[j].a; k <= v[j].b; k++)
+                                               nonempty |= (ix[j][k] - ix[j][k - 1] != 1);
 
                                vec = xrealloc_vector(vec, 6, ++idx);
                                memcpy(vec[idx], v, sizeof(v));
@@ -665,7 +678,7 @@ static bool diff(FILE* fp[2], char *file[2])
                                        continue;
                                printf(",%d", (a < b) ? b - a + 1 : 0);
                        }
-                       printf(" @@\n");
+                       puts(" @@");
                        /*
                         * Output changes in "unified" diff format--the old and new lines
                         * are printed together.
@@ -700,9 +713,19 @@ static int diffreg(char *file[2])
        fp[0] = stdin;
        fp[1] = stdin;
        for (i = 0; i < 2; i++) {
-               int fd = open_or_warn_stdin(file[i]);
-               if (fd == -1)
-                       goto out;
+               int fd = STDIN_FILENO;
+               if (!LONE_DASH(file[i])) {
+                       if (!(option_mask32 & FLAG(N))) {
+                               fd = open_or_warn(file[i], O_RDONLY);
+                               if (fd == -1)
+                                       goto out;
+                       } else {
+                               /* -N: if some file does not exist compare it like empty */
+                               fd = open(file[i], O_RDONLY);
+                               if (fd == -1)
+                                       fd = xopen("/dev/null", O_RDONLY);
+                       }
+               }
                /* Our diff implementation is using seek.
                 * When we meet non-seekable file, we must make a temp copy.
                 */
@@ -713,13 +736,15 @@ static int diffreg(char *file[2])
                        unlink(name);
                        if (bb_copyfd_eof(fd, fd_tmp) < 0)
                                xfunc_die();
-                       if (fd) /* Prevents closing of stdin */
+                       if (fd != STDIN_FILENO)
                                close(fd);
                        fd = fd_tmp;
+                       xlseek(fd, 0, SEEK_SET);
                }
                fp[i] = fdopen(fd, "r");
        }
 
+       setup_common_bufsiz();
        while (1) {
                const size_t sz = COMMON_BUFSIZE / 2;
                char *const buf0 = bb_common_bufsiz1;
@@ -940,6 +965,11 @@ static const char diff_longopts[] ALIGN1 =
        "starting-file\0"            Required_argument "S"
        "minimal\0"                  No_argument       "d"
        ;
+# define GETOPT32 getopt32long
+# define LONGOPTS ,diff_longopts
+#else
+# define GETOPT32 getopt32
+# define LONGOPTS
 #endif
 
 int diff_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -952,26 +982,29 @@ int diff_main(int argc UNUSED_PARAM, char **argv)
        INIT_G();
 
        /* exactly 2 params; collect multiple -L <label>; -U N */
-       opt_complementary = "=2:L::U+";
-#if ENABLE_FEATURE_DIFF_LONG_OPTIONS
-       applet_long_options = diff_longopts;
-#endif
-       getopt32(argv, "abdiL:NqrsS:tTU:wupBE",
+       GETOPT32(argv, "^" "abdiL:*NqrsS:tTU:+wupBE" "\0" "=2"
+                       LONGOPTS,
                        &L_arg, &s_start, &opt_U_context);
        argv += optind;
        while (L_arg)
                label[!!label[0]] = llist_pop(&L_arg);
+
+       /* Compat: "diff file name_which_doesnt_exist" exits with 2 */
        xfunc_error_retval = 2;
        for (i = 0; i < 2; i++) {
                file[i] = argv[i];
-               /* Compat: "diff file name_which_doesnt_exist" exits with 2 */
                if (LONE_DASH(file[i])) {
                        fstat(STDIN_FILENO, &stb[i]);
                        gotstdin++;
-               } else
+               } else if (option_mask32 & FLAG(N)) {
+                       if (stat(file[i], &stb[i]))
+                               xstat("/dev/null", &stb[i]);
+               } else {
                        xstat(file[i], &stb[i]);
+               }
        }
        xfunc_error_retval = 1;
+
        if (gotstdin && (S_ISDIR(stb[0].st_mode) || S_ISDIR(stb[1].st_mode)))
                bb_error_msg_and_die("can't compare stdin to a directory");