~ubuntu-branches/ubuntu/natty/diffutils/natty

« back to all changes in this revision

Viewing changes to src/cmp.c

  • Committer: Bazaar Package Importer
  • Author(s): Santiago Vila
  • Date: 2010-05-04 20:38:00 UTC
  • mfrom: (2.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100504203800-f67xd9rsa9xl9qqj
Tags: 1:3.0-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* cmp - compare two files byte by byte
2
2
 
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.
5
5
 
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)
9
 
   any later version.
 
8
   the Free Software Foundation, either version 3 of the License, or
 
9
   (at your option) any later version.
10
10
 
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.
15
15
 
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/>.  */
20
18
 
21
19
#include "system.h"
 
20
#include "paths.h"
22
21
 
23
22
#include <stdio.h>
 
23
 
 
24
#include <c-stack.h>
24
25
#include <cmpbuf.h>
25
 
#include <c-stack.h>
26
26
#include <error.h>
27
27
#include <exitfail.h>
28
 
#include <freesoft.h>
 
28
#include <file-type.h>
29
29
#include <getopt.h>
30
30
#include <hard-locale.h>
31
31
#include <inttostr.h>
32
 
#include <setmode.h>
 
32
#include <progname.h>
 
33
#include <unlocked-io.h>
 
34
#include <version-etc.h>
33
35
#include <xalloc.h>
 
36
#include <xfreopen.h>
34
37
#include <xstrtol.h>
35
38
 
 
39
/* The official name of this program (e.g., no `g' prefix).  */
 
40
#define PROGRAM_NAME "cmp"
 
41
 
 
42
#define AUTHORS \
 
43
  proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \
 
44
  proper_name ("David MacKenzie")
 
45
 
36
46
#if defined LC_MESSAGES && ENABLE_NLS
37
47
# define hard_locale_LC_MESSAGES hard_locale (LC_MESSAGES)
38
48
#else
39
49
# define hard_locale_LC_MESSAGES 0
40
50
#endif
41
51
 
42
 
static char const authorship_msgid[] =
43
 
  N_("Written by Torbjorn Granlund and David MacKenzie.");
44
 
 
45
 
static char const copyright_string[] =
46
 
  "Copyright (C) 2002 Free Software Foundation, Inc.";
47
 
 
48
 
extern char const version_string[];
49
 
 
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);
55
57
 
56
 
/* Name under which this program was invoked.  */
57
 
char *program_name;
58
 
 
59
58
/* Filenames of the compared files.  */
60
59
static char const *file[2];
61
60
 
82
81
  {
83
82
    type_first_diff,    /* Print the first difference.  */
84
83
    type_all_diffs,     /* Print all differences.  */
 
84
    type_no_stdout,     /* Do not output to stdout; only stderr.  */
85
85
    type_status         /* Exit status only.  */
86
86
  } comparison_type;
87
87
 
121
121
 
122
122
static char const valid_suffixes[] = "kKMGTPEZY0";
123
123
 
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.  */
127
 
static off_t
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.  */
 
128
static void
 
129
specify_ignore_initial (int f, char **argptr, char delimiter)
129
130
{
130
131
  uintmax_t val;
131
 
  off_t o;
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
 
  return o;
 
138
  if (ignore_initial[f] < val)
 
139
    ignore_initial[f] = val;
139
140
}
140
141
 
141
142
/* Specify the output format.  */
142
143
static void
143
144
specify_comparison_type (enum comparison_type t)
144
145
{
145
 
  if (comparison_type)
 
146
  if (comparison_type && comparison_type != t)
146
147
    try_help ("options -l and -s are incompatible", 0);
147
148
  comparison_type = t;
148
149
}
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 ();
189
191
}
190
192
 
191
193
int
196
198
 
197
199
  exit_failure = EXIT_TROUBLE;
198
200
  initialize_main (&argc, &argv);
199
 
  program_name = argv[0];
 
201
  set_program_name (argv[0]);
200
202
  setlocale (LC_ALL, "");
201
203
  bindtextdomain (PACKAGE, LOCALEDIR);
202
204
  textdomain (PACKAGE);
203
 
  c_stack_action (c_stack_die);
 
205
  c_stack_action (0);
204
206
 
205
207
  /* Parse command line options.  */
206
208
 
210
212
      {
211
213
      case 'b':
212
214
      case 'c': /* 'c' is obsolescent as of diffutils 2.7.3 */
213
 
        opt_print_bytes = 1;
 
215
        opt_print_bytes = true;
214
216
        break;
215
217
 
216
218
      case 'i':
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];
221
224
        break;
222
225
 
223
226
      case 'l':
239
242
        break;
240
243
 
241
244
      case 'v':
242
 
        printf ("cmp %s\n%s\n\n%s\n\n%s\n",
243
 
                version_string, copyright_string,
244
 
                _(free_software_msgid), _(authorship_msgid));
 
245
        version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, PACKAGE_VERSION,
 
246
                     AUTHORS, (char *) NULL);
245
247
        check_stdout ();
246
248
        return EXIT_SUCCESS;
247
249
 
263
265
  for (f = 0; f < 2 && optind < argc; f++)
264
266
    {
265
267
      char *arg = argv[optind++];
266
 
      ignore_initial[f] = parse_ignore_initial (&arg, 0);
 
268
      specify_ignore_initial (f, &arg, 0);
267
269
    }
268
270
 
269
271
  if (optind < argc)
273
275
    {
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], "-"));
277
279
 
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;
282
285
 
283
 
      file_desc[f1] = (strcmp (file[f1], "-") == 0
284
 
                       ? STDIN_FILENO
285
 
                       : open (file[f1], O_RDONLY, 0));
 
286
      if (STREQ (file[f1], "-"))
 
287
        {
 
288
          file_desc[f1] = STDIN_FILENO;
 
289
          if (O_BINARY && ! isatty (STDIN_FILENO))
 
290
            xfreopen (NULL, "rb", stdin);
 
291
        }
 
292
      else
 
293
        file_desc[f1] = open (file[f1], O_RDONLY | O_BINARY, 0);
 
294
 
286
295
      if (file_desc[f1] < 0 || fstat (file_desc[f1], stat_buf + f1) != 0)
287
296
        {
288
297
          if (file_desc[f1] < 0 && comparison_type == type_status)
290
299
          else
291
300
            error (EXIT_TROUBLE, errno, "%s", file[f1]);
292
301
        }
293
 
 
294
 
      set_binary_mode (file_desc[f1], 1);
295
302
    }
296
303
 
297
304
  /* If the files are links to the same inode and have the same file position,
302
309
      && file_position (0) == file_position (1))
303
310
    return EXIT_SUCCESS;
304
311
 
305
 
  /* If output is redirected to the null device, we may assume `-s'.  */
 
312
  /* If output is redirected to the null device, we can avoid some of
 
313
     the work.  */
306
314
 
307
315
  if (comparison_type != type_status)
308
316
    {
311
319
      if (fstat (STDOUT_FILENO, &outstat) == 0
312
320
          && stat (NULL_DEVICE, &nullstat) == 0
313
321
          && 0 < same_file (&outstat, &nullstat))
314
 
        comparison_type = type_status;
 
322
        comparison_type = type_no_stdout;
315
323
    }
316
324
 
317
325
  /* If only a return code is needed,
350
358
  for (f = 0; f < 2; f++)
351
359
    if (close (file_desc[f]) != 0)
352
360
      error (EXIT_TROUBLE, errno, "%s", file[f]);
353
 
  if (exit_status != 0  &&  comparison_type != type_status)
 
361
  if (exit_status != EXIT_SUCCESS && comparison_type < type_no_stdout)
354
362
    check_stdout ();
355
363
  exit (exit_status);
356
364
  return exit_status;
374
382
  word *buffer1 = buffer[1];
375
383
  char *buf0 = (char *) buffer0;
376
384
  char *buf1 = (char *) buffer1;
377
 
  int ret = EXIT_SUCCESS;
 
385
  int differing = 0;
378
386
  int f;
379
 
  int offset_width;
 
387
  int offset_width IF_LINT (= 0);
380
388
 
381
389
  if (comparison_type == type_all_diffs)
382
390
    {
479
487
                    bool use_byte_message = (byte_message != byte_msgid
480
488
                                             || hard_locale_LC_MESSAGES);
481
489
 
482
 
                    printf ((use_byte_message
483
 
                             ? 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);
486
492
                  }
487
493
                else
530
536
                  first_diff++;
531
537
                }
532
538
              while (first_diff < smaller);
533
 
              ret = EXIT_FAILURE;
 
539
              differing = -1;
 
540
              break;
 
541
 
 
542
            case type_no_stdout:
 
543
              differing = 1;
534
544
              break;
535
545
            }
536
546
        }
537
547
 
538
548
      if (read0 != read1)
539
549
        {
540
 
          if (comparison_type != type_status)
 
550
          if (differing <= 0 && comparison_type != type_status)
541
551
            {
542
552
              /* See POSIX 1003.1-2001 for this format.  */
543
553
              fprintf (stderr, _("cmp: EOF on %s\n"), file[read1 < read0]);
546
556
          return EXIT_FAILURE;
547
557
        }
548
558
    }
549
 
  while (read0 == buf_size);
 
559
  while (differing <= 0 && read0 == buf_size);
550
560
 
551
 
  return ret;
 
561
  return differing == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
552
562
}
553
563
 
554
564
/* Compare two blocks of memory P0 and P1 until they differ,
582
592
      l ^= nnnn;
583
593
      for (i = 0; i < sizeof l; i++)
584
594
        {
585
 
          cnt += ! (unsigned char) l;
 
595
          unsigned char uc = l;
 
596
          cnt += ! uc;
586
597
          l >>= CHAR_BIT;
587
598
        }
588
599
    }
632
643
static void
633
644
sprintc (char *buf, unsigned char c)
634
645
{
635
 
  if (! ISPRINT (c))
 
646
  if (! isprint (c))
636
647
    {
637
648
      if (c >= 128)
638
649
        {
667
678
 
668
679
  if (! positioned[f])
669
680
    {
670
 
      positioned[f] = 1;
 
681
      positioned[f] = true;
671
682
      position[f] = lseek (file_desc[f], ignore_initial[f], SEEK_CUR);
672
683
    }
673
684
  return position[f];