📄 cmp.c
字号:
/* 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 intcmp (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 : char_message, 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_tblock_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++) { unsigned char uc = l; cnt += ! uc; 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_tblock_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 voidsprintc (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_tfile_position (int f){ static bool positioned[2]; static off_t position[2]; if (! positioned[f]) { positioned[f] = true; position[f] = lseek (file_desc[f], ignore_initial[f], SEEK_CUR); } return position[f];}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -