summaryrefslogtreecommitdiff
path: root/gnu/dist/diffutils/src/cmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/dist/diffutils/src/cmp.c')
-rw-r--r--gnu/dist/diffutils/src/cmp.c676
1 files changed, 0 insertions, 676 deletions
diff --git a/gnu/dist/diffutils/src/cmp.c b/gnu/dist/diffutils/src/cmp.c
deleted file mode 100644
index d033829dfc6..00000000000
--- a/gnu/dist/diffutils/src/cmp.c
+++ /dev/null
@@ -1,676 +0,0 @@
-/* $NetBSD: cmp.c,v 1.1.1.1 2003/01/26 00:43:16 wiz Exp $ */
-
-/* cmp - compare two files byte by byte
-
- Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2001,
- 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING.
- If not, write to the Free Software Foundation,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include "system.h"
-
-#include <stdio.h>
-#include <cmpbuf.h>
-#include <c-stack.h>
-#include <error.h>
-#include <exitfail.h>
-#include <freesoft.h>
-#include <getopt.h>
-#include <hard-locale.h>
-#include <inttostr.h>
-#include <setmode.h>
-#include <xalloc.h>
-#include <xstrtol.h>
-
-#if defined LC_MESSAGES && ENABLE_NLS
-# define hard_locale_LC_MESSAGES hard_locale (LC_MESSAGES)
-#else
-# define hard_locale_LC_MESSAGES 0
-#endif
-
-static char const authorship_msgid[] =
- N_("Written by Torbjorn Granlund and David MacKenzie.");
-
-static char const copyright_string[] =
- "Copyright (C) 2002 Free Software Foundation, Inc.";
-
-extern char const version_string[];
-
-static int cmp (void);
-static off_t file_position (int);
-static size_t block_compare (word const *, word const *);
-static size_t block_compare_and_count (word const *, word const *, off_t *);
-static void sprintc (char *, unsigned char);
-
-/* Name under which this program was invoked. */
-char *program_name;
-
-/* Filenames of the compared files. */
-static char const *file[2];
-
-/* File descriptors of the files. */
-static int file_desc[2];
-
-/* Status of the files. */
-static struct stat stat_buf[2];
-
-/* Read buffers for the files. */
-static word *buffer[2];
-
-/* Optimal block size for the files. */
-static size_t buf_size;
-
-/* Initial prefix to ignore for each file. */
-static off_t ignore_initial[2];
-
-/* Number of bytes to compare. */
-static uintmax_t bytes = UINTMAX_MAX;
-
-/* Output format. */
-static enum comparison_type
- {
- type_first_diff, /* Print the first difference. */
- type_all_diffs, /* Print all differences. */
- type_status /* Exit status only. */
- } comparison_type;
-
-/* If nonzero, print values of bytes quoted like cat -t does. */
-static bool opt_print_bytes;
-
-/* Values for long options that do not have single-letter equivalents. */
-enum
-{
- HELP_OPTION = CHAR_MAX + 1
-};
-
-static struct option const long_options[] =
-{
- {"print-bytes", 0, 0, 'b'},
- {"print-chars", 0, 0, 'c'}, /* obsolescent as of diffutils 2.7.3 */
- {"ignore-initial", 1, 0, 'i'},
- {"verbose", 0, 0, 'l'},
- {"bytes", 1, 0, 'n'},
- {"silent", 0, 0, 's'},
- {"quiet", 0, 0, 's'},
- {"version", 0, 0, 'v'},
- {"help", 0, 0, HELP_OPTION},
- {0, 0, 0, 0}
-};
-
-static void try_help (char const *, char const *) __attribute__((noreturn));
-static void
-try_help (char const *reason_msgid, char const *operand)
-{
- if (reason_msgid)
- error (0, 0, _(reason_msgid), operand);
- error (EXIT_TROUBLE, 0,
- _("Try `%s --help' for more information."), program_name);
- abort ();
-}
-
-static char const valid_suffixes[] = "kKMGTPEZY0";
-
-/* Parse an operand *ARGPTR of --ignore-initial, updating *ARGPTR to
- point after the operand. If DELIMITER is nonzero, the operand may
- be followed by DELIMITER; otherwise it must be null-terminated. */
-static off_t
-parse_ignore_initial (char **argptr, char delimiter)
-{
- uintmax_t val;
- off_t o;
- char const *arg = *argptr;
- strtol_error e = xstrtoumax (arg, argptr, 0, &val, valid_suffixes);
- if (! (e == LONGINT_OK
- || (e == LONGINT_INVALID_SUFFIX_CHAR && **argptr == delimiter))
- || (o = val) < 0 || o != val || val == UINTMAX_MAX)
- try_help ("invalid --ignore-initial value `%s'", arg);
- return o;
-}
-
-/* Specify the output format. */
-static void
-specify_comparison_type (enum comparison_type t)
-{
- if (comparison_type)
- try_help ("options -l and -s are incompatible", 0);
- comparison_type = t;
-}
-
-static void
-check_stdout (void)
-{
- if (ferror (stdout))
- error (EXIT_TROUBLE, 0, "%s", _("write failed"));
- else if (fclose (stdout) != 0)
- error (EXIT_TROUBLE, errno, "%s", _("standard output"));
-}
-
-static char const * const option_help_msgid[] = {
- N_("-b --print-bytes Print differing bytes."),
- N_("-i SKIP --ignore-initial=SKIP Skip the first SKIP bytes of input."),
- N_("-i SKIP1:SKIP2 --ignore-initial=SKIP1:SKIP2"),
- N_(" Skip the first SKIP1 bytes of FILE1 and the first SKIP2 bytes of FILE2."),
- N_("-l --verbose Output byte numbers and values of all differing bytes."),
- N_("-n LIMIT --bytes=LIMIT Compare at most LIMIT bytes."),
- N_("-s --quiet --silent Output nothing; yield exit status only."),
- N_("-v --version Output version info."),
- N_("--help Output this help."),
- 0
-};
-
-static void
-usage (void)
-{
- char const * const *p;
-
- printf (_("Usage: %s [OPTION]... FILE1 [FILE2 [SKIP1 [SKIP2]]]\n"),
- program_name);
- printf ("%s\n\n", _("Compare two files byte by byte."));
- for (p = option_help_msgid; *p; p++)
- printf (" %s\n", _(*p));
- printf ("\n%s\n%s\n\n%s\n\n%s\n",
- _("SKIP1 and SKIP2 are the number of bytes to skip in each file."),
- _("SKIP values may be followed by the following multiplicative suffixes:\n\
-kB 1000, K 1024, MB 1,000,000, M 1,048,576,\n\
-GB 1,000,000,000, G 1,073,741,824, and so on for T, P, E, Z, Y."),
- _("If a FILE is `-' or missing, read standard input."),
- _("Report bugs to <bug-gnu-utils@gnu.org>."));
-}
-
-int
-main (int argc, char **argv)
-{
- int c, f, exit_status;
- size_t words_per_buffer;
-
- exit_failure = EXIT_TROUBLE;
- initialize_main (&argc, &argv);
- program_name = argv[0];
- setlocale (LC_ALL, "");
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
- c_stack_action (c_stack_die);
-
- /* Parse command line options. */
-
- while ((c = getopt_long (argc, argv, "bci:ln:sv", long_options, 0))
- != -1)
- switch (c)
- {
- case 'b':
- case 'c': /* 'c' is obsolescent as of diffutils 2.7.3 */
- opt_print_bytes = 1;
- break;
-
- case 'i':
- ignore_initial[0] = parse_ignore_initial (&optarg, ':');
- ignore_initial[1] = (*optarg++ == ':'
- ? parse_ignore_initial (&optarg, 0)
- : ignore_initial[0]);
- break;
-
- case 'l':
- specify_comparison_type (type_all_diffs);
- break;
-
- case 'n':
- {
- uintmax_t n;
- if (xstrtoumax (optarg, 0, 0, &n, valid_suffixes) != LONGINT_OK)
- try_help ("invalid --bytes value `%s'", optarg);
- if (n < bytes)
- bytes = n;
- }
- break;
-
- case 's':
- specify_comparison_type (type_status);
- break;
-
- case 'v':
- printf ("cmp %s\n%s\n\n%s\n\n%s\n",
- version_string, copyright_string,
- _(free_software_msgid), _(authorship_msgid));
- check_stdout ();
- return EXIT_SUCCESS;
-
- case HELP_OPTION:
- usage ();
- check_stdout ();
- return EXIT_SUCCESS;
-
- default:
- try_help (0, 0);
- }
-
- if (optind == argc)
- try_help ("missing operand after `%s'", argv[argc - 1]);
-
- file[0] = argv[optind++];
- file[1] = optind < argc ? argv[optind++] : "-";
-
- for (f = 0; f < 2 && optind < argc; f++)
- {
- char *arg = argv[optind++];
- ignore_initial[f] = parse_ignore_initial (&arg, 0);
- }
-
- if (optind < argc)
- try_help ("extra operand `%s'", argv[optind]);
-
- for (f = 0; f < 2; f++)
- {
- /* If file[1] is "-", treat it first; this avoids a misdiagnostic if
- stdin is closed and opening file[0] yields file descriptor 0. */
- int f1 = f ^ (strcmp (file[1], "-") == 0);
-
- /* Two files with the same name are identical.
- But wait until we open the file once, for proper diagnostics. */
- if (f && file_name_cmp (file[0], file[1]) == 0)
- return EXIT_SUCCESS;
-
- file_desc[f1] = (strcmp (file[f1], "-") == 0
- ? STDIN_FILENO
- : open (file[f1], O_RDONLY, 0));
- if (file_desc[f1] < 0 || fstat (file_desc[f1], stat_buf + f1) != 0)
- {
- if (file_desc[f1] < 0 && comparison_type == type_status)
- exit (EXIT_TROUBLE);
- else
- error (EXIT_TROUBLE, errno, "%s", file[f1]);
- }
-
- set_binary_mode (file_desc[f1], 1);
- }
-
- /* If the files are links to the same inode and have the same file position,
- they are identical. */
-
- if (0 < same_file (&stat_buf[0], &stat_buf[1])
- && same_file_attributes (&stat_buf[0], &stat_buf[1])
- && file_position (0) == file_position (1))
- return EXIT_SUCCESS;
-
- /* If output is redirected to the null device, we may assume `-s'. */
-
- if (comparison_type != type_status)
- {
- struct stat outstat, nullstat;
-
- if (fstat (STDOUT_FILENO, &outstat) == 0
- && stat (NULL_DEVICE, &nullstat) == 0
- && 0 < same_file (&outstat, &nullstat))
- comparison_type = type_status;
- }
-
- /* If only a return code is needed,
- and if both input descriptors are associated with plain files,
- conclude that the files differ if they have different sizes
- and if more bytes will be compared than are in the smaller file. */
-
- if (comparison_type == type_status
- && S_ISREG (stat_buf[0].st_mode)
- && S_ISREG (stat_buf[1].st_mode))
- {
- off_t s0 = stat_buf[0].st_size - file_position (0);
- off_t s1 = stat_buf[1].st_size - file_position (1);
- if (s0 < 0)
- s0 = 0;
- if (s1 < 0)
- s1 = 0;
- if (s0 != s1 && MIN (s0, s1) < bytes)
- exit (EXIT_FAILURE);
- }
-
- /* Get the optimal block size of the files. */
-
- buf_size = buffer_lcm (STAT_BLOCKSIZE (stat_buf[0]),
- STAT_BLOCKSIZE (stat_buf[1]),
- PTRDIFF_MAX - sizeof (word));
-
- /* Allocate word-aligned buffers, with space for sentinels at the end. */
-
- words_per_buffer = (buf_size + 2 * sizeof (word) - 1) / sizeof (word);
- buffer[0] = xmalloc (2 * sizeof (word) * words_per_buffer);
- buffer[1] = buffer[0] + words_per_buffer;
-
- exit_status = cmp ();
-
- for (f = 0; f < 2; f++)
- if (close (file_desc[f]) != 0)
- error (EXIT_TROUBLE, errno, "%s", file[f]);
- if (exit_status != 0 && comparison_type != type_status)
- check_stdout ();
- exit (exit_status);
- return exit_status;
-}
-
-/* Compare the two files already open on `file_desc[0]' and `file_desc[1]',
- using `buffer[0]' and `buffer[1]'.
- Return EXIT_SUCCESS if identical, EXIT_FAILURE if different,
- >1 if error. */
-
-static int
-cmp (void)
-{
- off_t line_number = 1; /* Line number (1...) of difference. */
- off_t byte_number = 1; /* Byte number (1...) of difference. */
- uintmax_t remaining = bytes; /* Remaining number of bytes to compare. */
- size_t read0, read1; /* Number of bytes read from each file. */
- size_t first_diff; /* Offset (0...) in buffers of 1st diff. */
- size_t smaller; /* The lesser of `read0' and `read1'. */
- word *buffer0 = buffer[0];
- word *buffer1 = buffer[1];
- char *buf0 = (char *) buffer0;
- char *buf1 = (char *) buffer1;
- int ret = EXIT_SUCCESS;
- int f;
- int offset_width;
-
- if (comparison_type == type_all_diffs)
- {
- off_t byte_number_max = MIN (bytes, TYPE_MAXIMUM (off_t));
-
- for (f = 0; f < 2; f++)
- if (S_ISREG (stat_buf[f].st_mode))
- {
- off_t file_bytes = stat_buf[f].st_size - file_position (f);
- if (file_bytes < byte_number_max)
- byte_number_max = file_bytes;
- }
-
- for (offset_width = 1; (byte_number_max /= 10) != 0; offset_width++)
- continue;
- }
-
- for (f = 0; f < 2; f++)
- {
- off_t ig = ignore_initial[f];
- if (ig && file_position (f) == -1)
- {
- /* lseek failed; read and discard the ignored initial prefix. */
- do
- {
- size_t bytes_to_read = MIN (ig, buf_size);
- size_t r = block_read (file_desc[f], buf0, bytes_to_read);
- if (r != bytes_to_read)
- {
- if (r == SIZE_MAX)
- error (EXIT_TROUBLE, errno, "%s", file[f]);
- break;
- }
- ig -= r;
- }
- while (ig);
- }
- }
-
- do
- {
- size_t bytes_to_read = buf_size;
-
- if (remaining != UINTMAX_MAX)
- {
- if (remaining < bytes_to_read)
- bytes_to_read = remaining;
- remaining -= bytes_to_read;
- }
-
- read0 = block_read (file_desc[0], buf0, bytes_to_read);
- if (read0 == SIZE_MAX)
- error (EXIT_TROUBLE, errno, "%s", file[0]);
- read1 = block_read (file_desc[1], buf1, bytes_to_read);
- if (read1 == SIZE_MAX)
- error (EXIT_TROUBLE, errno, "%s", file[1]);
-
- /* Insert sentinels for the block compare. */
-
- buf0[read0] = ~buf1[read0];
- buf1[read1] = ~buf0[read1];
-
- /* If the line number should be written for differing files,
- compare the blocks and count the number of newlines
- simultaneously. */
- first_diff = (comparison_type == type_first_diff
- ? block_compare_and_count (buffer0, buffer1, &line_number)
- : block_compare (buffer0, buffer1));
-
- byte_number += first_diff;
- smaller = MIN (read0, read1);
-
- if (first_diff < smaller)
- {
- switch (comparison_type)
- {
- case type_first_diff:
- {
- char byte_buf[INT_BUFSIZE_BOUND (off_t)];
- char line_buf[INT_BUFSIZE_BOUND (off_t)];
- char const *byte_num = offtostr (byte_number, byte_buf);
- char const *line_num = offtostr (line_number, line_buf);
- if (!opt_print_bytes)
- {
- /* See POSIX 1003.1-2001 for this format. This
- message is used only in the POSIX locale, so it
- need not be translated. */
- static char const char_message[] =
- "%s %s differ: char %s, line %s\n";
-
- /* The POSIX rationale recommends using the word
- "byte" outside the POSIX locale. Some gettext
- implementations translate even in the POSIX
- locale if certain other environment variables
- are set, so use "byte" if a translation is
- available, or if outside the POSIX locale. */
- static char const byte_msgid[] =
- N_("%s %s differ: byte %s, line %s\n");
- char const *byte_message = _(byte_msgid);
- bool use_byte_message = (byte_message != byte_msgid
- || hard_locale_LC_MESSAGES);
-
- printf ((use_byte_message
- ? byte_message
- : "%s %s differ: char %s, line %s\n"),
- file[0], file[1], byte_num, line_num);
- }
- else
- {
- unsigned char c0 = buf0[first_diff];
- unsigned char c1 = buf1[first_diff];
- char s0[5];
- char s1[5];
- sprintc (s0, c0);
- sprintc (s1, c1);
- printf (_("%s %s differ: byte %s, line %s is %3o %s %3o %s\n"),
- file[0], file[1], byte_num, line_num,
- c0, s0, c1, s1);
- }
- }
- /* Fall through. */
- case type_status:
- return EXIT_FAILURE;
-
- case type_all_diffs:
- do
- {
- unsigned char c0 = buf0[first_diff];
- unsigned char c1 = buf1[first_diff];
- if (c0 != c1)
- {
- char byte_buf[INT_BUFSIZE_BOUND (off_t)];
- char const *byte_num = offtostr (byte_number, byte_buf);
- if (!opt_print_bytes)
- {
- /* See POSIX 1003.1-2001 for this format. */
- printf ("%*s %3o %3o\n",
- offset_width, byte_num, c0, c1);
- }
- else
- {
- char s0[5];
- char s1[5];
- sprintc (s0, c0);
- sprintc (s1, c1);
- printf ("%*s %3o %-4s %3o %s\n",
- offset_width, byte_num, c0, s0, c1, s1);
- }
- }
- byte_number++;
- first_diff++;
- }
- while (first_diff < smaller);
- ret = EXIT_FAILURE;
- break;
- }
- }
-
- if (read0 != read1)
- {
- if (comparison_type != type_status)
- {
- /* See POSIX 1003.1-2001 for this format. */
- fprintf (stderr, _("cmp: EOF on %s\n"), file[read1 < read0]);
- }
-
- return EXIT_FAILURE;
- }
- }
- while (read0 == buf_size);
-
- return ret;
-}
-
-/* Compare two blocks of memory P0 and P1 until they differ,
- and count the number of '\n' occurrences in the common
- part of P0 and P1.
- If the blocks are not guaranteed to be different, put sentinels at the ends
- of the blocks before calling this function.
-
- Return the offset of the first byte that differs.
- Increment *COUNT by the count of '\n' occurrences. */
-
-static size_t
-block_compare_and_count (word const *p0, word const *p1, off_t *count)
-{
- word l; /* One word from first buffer. */
- word const *l0, *l1; /* Pointers into each buffer. */
- char const *c0, *c1; /* Pointers for finding exact address. */
- size_t cnt = 0; /* Number of '\n' occurrences. */
- word nnnn; /* Newline, sizeof (word) times. */
- int i;
-
- nnnn = 0;
- for (i = 0; i < sizeof nnnn; i++)
- nnnn = (nnnn << CHAR_BIT) | '\n';
-
- /* Find the rough position of the first difference by reading words,
- not bytes. */
-
- for (l0 = p0, l1 = p1; (l = *l0) == *l1; l0++, l1++)
- {
- l ^= nnnn;
- for (i = 0; i < sizeof l; i++)
- {
- cnt += ! (unsigned char) l;
- l >>= CHAR_BIT;
- }
- }
-
- /* Find the exact differing position (endianness independent). */
-
- for (c0 = (char const *) l0, c1 = (char const *) l1;
- *c0 == *c1;
- c0++, c1++)
- cnt += *c0 == '\n';
-
- *count += cnt;
- return c0 - (char const *) p0;
-}
-
-/* Compare two blocks of memory P0 and P1 until they differ.
- If the blocks are not guaranteed to be different, put sentinels at the ends
- of the blocks before calling this function.
-
- Return the offset of the first byte that differs. */
-
-static size_t
-block_compare (word const *p0, word const *p1)
-{
- word const *l0, *l1;
- char const *c0, *c1;
-
- /* Find the rough position of the first difference by reading words,
- not bytes. */
-
- for (l0 = p0, l1 = p1; *l0 == *l1; l0++, l1++)
- continue;
-
- /* Find the exact differing position (endianness independent). */
-
- for (c0 = (char const *) l0, c1 = (char const *) l1;
- *c0 == *c1;
- c0++, c1++)
- continue;
-
- return c0 - (char const *) p0;
-}
-
-/* Put into BUF the unsigned char C, making unprintable bytes
- visible by quoting like cat -t does. */
-
-static void
-sprintc (char *buf, unsigned char c)
-{
- if (! ISPRINT (c))
- {
- if (c >= 128)
- {
- *buf++ = 'M';
- *buf++ = '-';
- c -= 128;
- }
- if (c < 32)
- {
- *buf++ = '^';
- c += 64;
- }
- else if (c == 127)
- {
- *buf++ = '^';
- c = '?';
- }
- }
-
- *buf++ = c;
- *buf = 0;
-}
-
-/* Position file F to ignore_initial[F] bytes from its initial position,
- and yield its new position. Don't try more than once. */
-
-static off_t
-file_position (int f)
-{
- static bool positioned[2];
- static off_t position[2];
-
- if (! positioned[f])
- {
- positioned[f] = 1;
- position[f] = lseek (file_desc[f], ignore_initial[f], SEEK_CUR);
- }
- return position[f];
-}