1
1
/* cmp - compare two files byte by byte
3
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2001,
4
2002 Free Software Foundation, Inc.
3
Copyright (C) 1990-1996, 1998, 2001-2002, 2004, 2006-2007, 2009-2010 Free
4
Software Foundation, Inc.
6
This program is free software; you can redistribute it and/or modify
6
This program is free software: you can redistribute it and/or modify
7
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
8
the Free Software Foundation, either version 3 of the License, or
9
(at your option) any later version.
11
11
This program is distributed in the hope that it will be useful,
12
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
See the GNU General Public License for more details.
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
16
You should have received a copy of the GNU General Public License
17
along with this program; see the file COPYING.
18
If not, write to the Free Software Foundation,
19
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
19
#include "system.h"
24
25
#include <cmpbuf.h>
27
27
#include <exitfail.h>
28
#include <file-type.h>
29
29
#include <getopt.h>
30
30
#include <hard-locale.h>
31
31
#include <inttostr.h>
33
#include <unlocked-io.h>
34
#include <version-etc.h>
33
35
#include <xalloc.h>
34
37
#include <xstrtol.h>
39
/* The official name of this program (e.g., no `g' prefix). */
40
#define PROGRAM_NAME "cmp"
43
proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \
44
proper_name ("David MacKenzie")
36
46
#if defined LC_MESSAGES && ENABLE_NLS
37
47
# define hard_locale_LC_MESSAGES hard_locale (LC_MESSAGES)
39
49
# define hard_locale_LC_MESSAGES 0
42
static char const authorship_msgid[] =
43
N_("Written by Torbjorn Granlund and David MacKenzie.");
45
static char const copyright_string[] =
46
"Copyright (C) 2002 Free Software Foundation, Inc.";
48
extern char const version_string[];
50
52
static int cmp (void);
51
53
static off_t file_position (int);
52
54
static size_t block_compare (word const *, word const *);
53
55
static size_t block_compare_and_count (word const *, word const *, off_t *);
54
56
static void sprintc (char *, unsigned char);
56
/* Name under which this program was invoked. */
59
58
/* Filenames of the compared files. */
60
59
static char const *file[2];
122
122
static char const valid_suffixes[] = "kKMGTPEZY0";
124
/* Parse an operand *ARGPTR of --ignore-initial, updating *ARGPTR to
125
point after the operand. If DELIMITER is nonzero, the operand may
126
be followed by DELIMITER; otherwise it must be null-terminated. */
128
parse_ignore_initial (char **argptr, char delimiter)
124
/* Update ignore_initial[F] according to the result of parsing an
125
*operand ARGPTR of --ignore-initial, updating *ARGPTR to point
126
*after the operand. If DELIMITER is nonzero, the operand may be
127
*followed by DELIMITER; otherwise it must be null-terminated. */
129
specify_ignore_initial (int f, char **argptr, char delimiter)
132
132
char const *arg = *argptr;
133
133
strtol_error e = xstrtoumax (arg, argptr, 0, &val, valid_suffixes);
134
134
if (! (e == LONGINT_OK
135
135
|| (e == LONGINT_INVALID_SUFFIX_CHAR && **argptr == delimiter))
136
|| (o = val) < 0 || o != val || val == UINTMAX_MAX)
136
|| TYPE_MAXIMUM (off_t) < val)
137
137
try_help ("invalid --ignore-initial value `%s'", arg);
138
if (ignore_initial[f] < val)
139
ignore_initial[f] = val;
141
142
/* Specify the output format. */
143
144
specify_comparison_type (enum comparison_type t)
146
if (comparison_type && comparison_type != t)
146
147
try_help ("options -l and -s are incompatible", 0);
147
148
comparison_type = t;
179
180
printf ("%s\n\n", _("Compare two files byte by byte."));
180
181
for (p = option_help_msgid; *p; p++)
181
182
printf (" %s\n", _(*p));
182
printf ("\n%s\n%s\n\n%s\n\n%s\n",
183
printf ("\n%s\n%s\n\n%s\n%s\n",
183
184
_("SKIP1 and SKIP2 are the number of bytes to skip in each file."),
184
185
_("SKIP values may be followed by the following multiplicative suffixes:\n\
185
186
kB 1000, K 1024, MB 1,000,000, M 1,048,576,\n\
186
187
GB 1,000,000,000, G 1,073,741,824, and so on for T, P, E, Z, Y."),
187
188
_("If a FILE is `-' or missing, read standard input."),
188
_("Report bugs to <bug-gnu-utils@gnu.org>."));
189
_("Exit status is 0 if inputs are the same, 1 if different, 2 if trouble."));
190
emit_bug_reporting_address ();
212
214
case 'c': /* 'c' is obsolescent as of diffutils 2.7.3 */
215
opt_print_bytes = true;
217
ignore_initial[0] = parse_ignore_initial (&optarg, ':');
218
ignore_initial[1] = (*optarg++ == ':'
219
? parse_ignore_initial (&optarg, 0)
220
: ignore_initial[0]);
219
specify_ignore_initial (0, &optarg, ':');
220
if (*optarg++ == ':')
221
specify_ignore_initial (1, &optarg, 0);
222
else if (ignore_initial[1] < ignore_initial[0])
223
ignore_initial[1] = ignore_initial[0];
274
276
/* If file[1] is "-", treat it first; this avoids a misdiagnostic if
275
277
stdin is closed and opening file[0] yields file descriptor 0. */
276
int f1 = f ^ (strcmp (file[1], "-") == 0);
278
int f1 = f ^ (STREQ (file[1], "-"));
278
/* Two files with the same name are identical.
280
/* Two files with the same name and offset are identical.
279
281
But wait until we open the file once, for proper diagnostics. */
280
if (f && file_name_cmp (file[0], file[1]) == 0)
282
if (f && ignore_initial[0] == ignore_initial[1]
283
&& file_name_cmp (file[0], file[1]) == 0)
281
284
return EXIT_SUCCESS;
283
file_desc[f1] = (strcmp (file[f1], "-") == 0
285
: open (file[f1], O_RDONLY, 0));
286
if (STREQ (file[f1], "-"))
288
file_desc[f1] = STDIN_FILENO;
289
if (O_BINARY && ! isatty (STDIN_FILENO))
290
xfreopen (NULL, "rb", stdin);
293
file_desc[f1] = open (file[f1], O_RDONLY | O_BINARY, 0);
286
295
if (file_desc[f1] < 0 || fstat (file_desc[f1], stat_buf + f1) != 0)
288
297
if (file_desc[f1] < 0 && comparison_type == type_status)
479
487
bool use_byte_message = (byte_message != byte_msgid
480
488
|| hard_locale_LC_MESSAGES);
482
printf ((use_byte_message
484
: "%s %s differ: char %s, line %s\n"),
490
printf (use_byte_message ? byte_message : char_message,
485
491
file[0], file[1], byte_num, line_num);