1 /* GNU diff - compare files line by line
3 Copyright (C) 1988-1989, 1992-1994, 1996, 1998, 2001-2002, 2004, 2006-2007,
4 2009-2013, 2015-2018 Free Software Foundation, Inc.
6 This file is part of GNU DIFF.
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
31 #include <filenamecat.h>
32 #include <file-type.h>
35 #include <hard-locale.h>
39 #include <stat-time.h>
41 #include <version-etc.h>
43 #include <xreadlink.h>
44 #include <binary-io.h>
46 /* The official name of this program (e.g., no 'g' prefix). */
47 #define PROGRAM_NAME "diff"
50 proper_name ("Paul Eggert"), \
51 proper_name ("Mike Haertel"), \
52 proper_name ("David Hayes"), \
53 proper_name ("Richard Stallman"), \
54 proper_name ("Len Tower")
56 #ifndef GUTTER_WIDTH_MINIMUM
57 # define GUTTER_WIDTH_MINIMUM 3
62 char *regexps; /* chars representing disjunction of the regexps */
63 size_t len; /* chars used in 'regexps' */
64 size_t size; /* size malloc'ed for 'regexps'; 0 if not malloc'ed */
65 bool multiple_regexps;/* Does 'regexps' represent a disjunction? */
66 struct re_pattern_buffer *buf;
69 static int compare_files (struct comparison const *, char const *, char const *);
70 static void add_regexp (struct regexp_list *, char const *);
71 static void summarize_regexp_list (struct regexp_list *);
72 static void specify_style (enum output_style);
73 static void specify_value (char const **, char const *, char const *);
74 static void specify_colors_style (char const *);
75 static void try_help (char const *, char const *) __attribute__((noreturn));
76 static void check_stdout (void);
77 static void usage (void);
79 /* If comparing directories, compare their common subdirectories
81 static bool recursive;
83 /* In context diffs, show previous lines that match these regexps. */
84 static struct regexp_list function_regexp_list;
86 /* Ignore changes affecting only lines that match these regexps. */
87 static struct regexp_list ignore_regexp_list;
90 /* Use binary I/O when reading and writing data (--binary).
91 On POSIX hosts, this has no effect. */
94 enum { binary = true };
97 /* If one file is missing, treat it as present but empty (-N). */
100 /* If the first file is missing, treat it as present but empty
101 (--unidirectional-new-file). */
102 static bool unidirectional_new_file;
104 /* Report files compared that are the same (-s).
105 Normally nothing is output when that happens. */
106 static bool report_identical_files;
108 static char const shortopts[] =
109 "0123456789abBcC:dD:eEfF:hHiI:lL:nNpPqrsS:tTuU:vwW:x:X:yZ";
111 /* Values for long options that do not have single-letter equivalents. */
114 BINARY_OPTION = CHAR_MAX + 1,
117 HORIZON_LINES_OPTION,
118 IGNORE_FILE_NAME_CASE_OPTION,
119 INHIBIT_HUNK_MERGE_OPTION,
122 NO_DEREFERENCE_OPTION,
123 NO_IGNORE_FILE_NAME_CASE_OPTION,
125 SDIFF_MERGE_ASSIST_OPTION,
126 STRIP_TRAILING_CR_OPTION,
127 SUPPRESS_BLANK_EMPTY_OPTION,
128 SUPPRESS_COMMON_LINES_OPTION,
132 /* These options must be in sequence. */
133 UNCHANGED_LINE_FORMAT_OPTION,
134 OLD_LINE_FORMAT_OPTION,
135 NEW_LINE_FORMAT_OPTION,
137 /* These options must be in sequence. */
138 UNCHANGED_GROUP_FORMAT_OPTION,
139 OLD_GROUP_FORMAT_OPTION,
140 NEW_GROUP_FORMAT_OPTION,
141 CHANGED_GROUP_FORMAT_OPTION,
144 COLOR_PALETTE_OPTION,
146 PRESUME_OUTPUT_TTY_OPTION,
149 static char const group_format_option[][sizeof "--unchanged-group-format"] =
151 "--unchanged-group-format",
152 "--old-group-format",
153 "--new-group-format",
154 "--changed-group-format"
157 static char const line_format_option[][sizeof "--unchanged-line-format"] =
159 "--unchanged-line-format",
164 static struct option const longopts[] =
166 {"binary", 0, 0, BINARY_OPTION},
167 {"brief", 0, 0, 'q'},
168 {"changed-group-format", 1, 0, CHANGED_GROUP_FORMAT_OPTION},
169 {"color", 2, 0, COLOR_OPTION},
170 {"context", 2, 0, 'C'},
172 {"exclude", 1, 0, 'x'},
173 {"exclude-from", 1, 0, 'X'},
174 {"expand-tabs", 0, 0, 't'},
175 {"forward-ed", 0, 0, 'f'},
176 {"from-file", 1, 0, FROM_FILE_OPTION},
177 {"help", 0, 0, HELP_OPTION},
178 {"horizon-lines", 1, 0, HORIZON_LINES_OPTION},
179 {"ifdef", 1, 0, 'D'},
180 {"ignore-all-space", 0, 0, 'w'},
181 {"ignore-blank-lines", 0, 0, 'B'},
182 {"ignore-case", 0, 0, 'i'},
183 {"ignore-file-name-case", 0, 0, IGNORE_FILE_NAME_CASE_OPTION},
184 {"ignore-matching-lines", 1, 0, 'I'},
185 {"ignore-space-change", 0, 0, 'b'},
186 {"ignore-tab-expansion", 0, 0, 'E'},
187 {"ignore-trailing-space", 0, 0, 'Z'},
188 {"inhibit-hunk-merge", 0, 0, INHIBIT_HUNK_MERGE_OPTION},
189 {"initial-tab", 0, 0, 'T'},
190 {"label", 1, 0, 'L'},
191 {"left-column", 0, 0, LEFT_COLUMN_OPTION},
192 {"line-format", 1, 0, LINE_FORMAT_OPTION},
193 {"minimal", 0, 0, 'd'},
194 {"new-file", 0, 0, 'N'},
195 {"new-group-format", 1, 0, NEW_GROUP_FORMAT_OPTION},
196 {"new-line-format", 1, 0, NEW_LINE_FORMAT_OPTION},
197 {"no-dereference", 0, 0, NO_DEREFERENCE_OPTION},
198 {"no-ignore-file-name-case", 0, 0, NO_IGNORE_FILE_NAME_CASE_OPTION},
199 {"normal", 0, 0, NORMAL_OPTION},
200 {"old-group-format", 1, 0, OLD_GROUP_FORMAT_OPTION},
201 {"old-line-format", 1, 0, OLD_LINE_FORMAT_OPTION},
202 {"paginate", 0, 0, 'l'},
203 {"palette", 1, 0, COLOR_PALETTE_OPTION},
205 {"recursive", 0, 0, 'r'},
206 {"report-identical-files", 0, 0, 's'},
207 {"sdiff-merge-assist", 0, 0, SDIFF_MERGE_ASSIST_OPTION},
208 {"show-c-function", 0, 0, 'p'},
209 {"show-function-line", 1, 0, 'F'},
210 {"side-by-side", 0, 0, 'y'},
211 {"speed-large-files", 0, 0, 'H'},
212 {"starting-file", 1, 0, 'S'},
213 {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},
214 {"suppress-blank-empty", 0, 0, SUPPRESS_BLANK_EMPTY_OPTION},
215 {"suppress-common-lines", 0, 0, SUPPRESS_COMMON_LINES_OPTION},
216 {"tabsize", 1, 0, TABSIZE_OPTION},
218 {"to-file", 1, 0, TO_FILE_OPTION},
219 {"unchanged-group-format", 1, 0, UNCHANGED_GROUP_FORMAT_OPTION},
220 {"unchanged-line-format", 1, 0, UNCHANGED_LINE_FORMAT_OPTION},
221 {"unidirectional-new-file", 0, 0, 'P'},
222 {"unified", 2, 0, 'U'},
223 {"version", 0, 0, 'v'},
224 {"width", 1, 0, 'W'},
226 /* This is solely for testing. Do not document. */
227 {"-presume-output-tty", no_argument, NULL, PRESUME_OUTPUT_TTY_OPTION},
231 /* Return a string containing the command options with which diff was invoked.
232 Spaces appear between what were separate ARGV-elements.
233 There is a space at the beginning but none at the end.
234 If there were no options, the result is an empty string.
236 Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT,
237 the length of that vector. */
240 option_list (char **optionvec, int count)
247 for (i = 0; i < count; i++)
248 size += 1 + shell_quote_length (optionvec[i]);
250 p = result = xmalloc (size);
252 for (i = 0; i < count; i++)
255 p = shell_quote_copy (p, optionvec[i]);
263 /* Return an option value suitable for add_exclude. */
266 exclude_options (void)
268 return EXCLUDE_WILDCARDS | (ignore_file_name_case ? FNM_CASEFOLD : 0);
272 main (int argc, char **argv)
274 int exit_status = EXIT_SUCCESS;
279 bool explicit_context = false;
281 bool show_c_function = false;
282 char const *from_file = NULL;
283 char const *to_file = NULL;
287 /* Do our initializations. */
288 exit_failure = EXIT_TROUBLE;
289 initialize_main (&argc, &argv);
290 set_program_name (argv[0]);
291 setlocale (LC_ALL, "");
292 bindtextdomain (PACKAGE, LOCALEDIR);
293 textdomain (PACKAGE);
295 function_regexp_list.buf = &function_regexp;
296 ignore_regexp_list.buf = &ignore_regexp;
297 re_set_syntax (RE_SYNTAX_GREP | RE_NO_POSIX_BACKTRACKING);
298 excluded = new_exclude ();
299 presume_output_tty = false;
301 /* Decode the options. */
303 while ((c = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
320 ocontext = (! ISDIGIT (prev)
322 : (ocontext - (c - '0' <= CONTEXT_MAX % 10)
324 ? 10 * ocontext + (c - '0')
333 if (ignore_white_space < IGNORE_SPACE_CHANGE)
334 ignore_white_space = IGNORE_SPACE_CHANGE;
338 if (ignore_white_space < IGNORE_SPACE_CHANGE)
339 ignore_white_space |= IGNORE_TRAILING_SPACE;
343 ignore_blank_lines = true;
351 numval = strtoumax (optarg, &numend, 10);
353 try_help ("invalid context length '%s'", optarg);
354 if (CONTEXT_MAX < numval)
355 numval = CONTEXT_MAX;
360 specify_style (c == 'U' ? OUTPUT_UNIFIED : OUTPUT_CONTEXT);
361 if (context < numval)
363 explicit_context = true;
368 specify_style (OUTPUT_CONTEXT);
378 specify_style (OUTPUT_IFDEF);
380 static char const C_ifdef_group_formats[] =
381 "%%=%c#ifndef %s\n%%<#endif /* ! %s */\n%c#ifdef %s\n%%>#endif /* %s */\n%c#ifndef %s\n%%<#else /* %s */\n%%>#endif /* %s */\n";
382 char *b = xmalloc (sizeof C_ifdef_group_formats
383 + 7 * strlen (optarg) - 14 /* 7*"%s" */
384 - 8 /* 5*"%%" + 3*"%c" */);
385 sprintf (b, C_ifdef_group_formats,
389 optarg, optarg, optarg);
390 for (i = 0; i < sizeof group_format / sizeof group_format[0]; i++)
392 specify_value (&group_format[i], b, "-D");
399 specify_style (OUTPUT_ED);
403 if (ignore_white_space < IGNORE_SPACE_CHANGE)
404 ignore_white_space |= IGNORE_TAB_EXPANSION;
408 specify_style (OUTPUT_FORWARD_ED);
412 add_regexp (&function_regexp_list, optarg);
416 /* Split the files into chunks for faster processing.
417 Usually does not change the result.
419 This currently has no effect. */
423 speed_large_files = true;
431 add_regexp (&ignore_regexp_list, optarg);
436 try_help ("pagination not supported on this host", NULL);
439 /* Pagination requires forking and waiting, and
440 System V fork+wait does not work if SIGCHLD is ignored. */
441 signal (SIGCHLD, SIG_DFL);
447 file_label[0] = optarg;
448 else if (!file_label[1])
449 file_label[1] = optarg;
451 fatal ("too many file label options");
455 specify_style (OUTPUT_RCS);
463 show_c_function = true;
464 add_regexp (&function_regexp_list, "^[[:alpha:]$_]");
468 unidirectional_new_file = true;
480 report_identical_files = true;
484 specify_value (&starting_file, optarg, "-S");
496 specify_style (OUTPUT_UNIFIED);
502 version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version,
503 AUTHORS, (char *) NULL);
508 ignore_white_space = IGNORE_ALL_SPACE;
512 add_exclude (excluded, optarg, exclude_options ());
516 if (add_exclude_file (add_exclude, excluded, optarg,
517 exclude_options (), '\n'))
518 pfatal_with_name (optarg);
522 specify_style (OUTPUT_SDIFF);
526 numval = strtoumax (optarg, &numend, 10);
527 if (! (0 < numval && numval <= SIZE_MAX) || *numend)
528 try_help ("invalid width '%s'", optarg);
532 fatal ("conflicting width options");
540 if (! isatty (STDOUT_FILENO))
541 set_binary_mode (STDOUT_FILENO, O_BINARY);
545 case FROM_FILE_OPTION:
546 specify_value (&from_file, optarg, "--from-file");
554 case HORIZON_LINES_OPTION:
555 numval = strtoumax (optarg, &numend, 10);
557 try_help ("invalid horizon length '%s'", optarg);
558 horizon_lines = MAX (horizon_lines, MIN (numval, LIN_MAX));
561 case IGNORE_FILE_NAME_CASE_OPTION:
562 ignore_file_name_case = true;
565 case INHIBIT_HUNK_MERGE_OPTION:
566 /* This option is obsolete, but accept it for backward
570 case LEFT_COLUMN_OPTION:
574 case LINE_FORMAT_OPTION:
575 specify_style (OUTPUT_IFDEF);
576 for (i = 0; i < sizeof line_format / sizeof line_format[0]; i++)
577 specify_value (&line_format[i], optarg, "--line-format");
580 case NO_DEREFERENCE_OPTION:
581 no_dereference_symlinks = true;
584 case NO_IGNORE_FILE_NAME_CASE_OPTION:
585 ignore_file_name_case = false;
589 specify_style (OUTPUT_NORMAL);
592 case SDIFF_MERGE_ASSIST_OPTION:
593 specify_style (OUTPUT_SDIFF);
594 sdiff_merge_assist = true;
597 case STRIP_TRAILING_CR_OPTION:
598 strip_trailing_cr = true;
601 case SUPPRESS_BLANK_EMPTY_OPTION:
602 suppress_blank_empty = true;
605 case SUPPRESS_COMMON_LINES_OPTION:
606 suppress_common_lines = true;
610 numval = strtoumax (optarg, &numend, 10);
611 if (! (0 < numval && numval <= SIZE_MAX - GUTTER_WIDTH_MINIMUM)
613 try_help ("invalid tabsize '%s'", optarg);
614 if (tabsize != numval)
617 fatal ("conflicting tabsize options");
623 specify_value (&to_file, optarg, "--to-file");
626 case UNCHANGED_LINE_FORMAT_OPTION:
627 case OLD_LINE_FORMAT_OPTION:
628 case NEW_LINE_FORMAT_OPTION:
629 specify_style (OUTPUT_IFDEF);
630 c -= UNCHANGED_LINE_FORMAT_OPTION;
631 specify_value (&line_format[c], optarg, line_format_option[c]);
634 case UNCHANGED_GROUP_FORMAT_OPTION:
635 case OLD_GROUP_FORMAT_OPTION:
636 case NEW_GROUP_FORMAT_OPTION:
637 case CHANGED_GROUP_FORMAT_OPTION:
638 specify_style (OUTPUT_IFDEF);
639 c -= UNCHANGED_GROUP_FORMAT_OPTION;
640 specify_value (&group_format[c], optarg, group_format_option[c]);
644 specify_colors_style (optarg);
647 case COLOR_PALETTE_OPTION:
648 set_color_palette (optarg);
651 case PRESUME_OUTPUT_TTY_OPTION:
652 presume_output_tty = true;
656 try_help (NULL, NULL);
661 if (colors_style == AUTO)
663 char const *t = getenv ("TERM");
664 if (t && STREQ (t, "dumb"))
665 colors_style = NEVER;
668 if (output_style == OUTPUT_UNSPECIFIED)
672 specify_style (OUTPUT_CONTEXT);
677 specify_style (OUTPUT_NORMAL);
680 if (output_style != OUTPUT_CONTEXT || hard_locale (LC_TIME))
682 #if (defined STAT_TIMESPEC || defined STAT_TIMESPEC_NS \
683 || defined HAVE_STRUCT_STAT_ST_SPARE1)
684 time_format = "%Y-%m-%d %H:%M:%S.%N %z";
686 time_format = "%Y-%m-%d %H:%M:%S %z";
691 /* See POSIX 1003.1-2001 for this format. */
692 time_format = "%a %b %e %T %Y";
696 && (output_style == OUTPUT_CONTEXT
697 || output_style == OUTPUT_UNIFIED)
698 && (context < ocontext
699 || (ocontext < context && ! explicit_context)))
708 /* Maximize first the half line width, and then the gutter width,
709 according to the following constraints:
711 1. Two half lines plus a gutter must fit in a line.
712 2. If the half line width is nonzero:
713 a. The gutter width is at least GUTTER_WIDTH_MINIMUM.
714 b. If tabs are not expanded to spaces,
715 a half line plus a gutter is an integral number of tabs,
716 so that tabs in the right column line up. */
718 size_t t = expand_tabs ? 1 : tabsize;
720 size_t t_plus_g = t + GUTTER_WIDTH_MINIMUM;
721 size_t unaligned_off = (w >> 1) + (t_plus_g >> 1) + (w & t_plus_g & 1);
722 size_t off = unaligned_off - unaligned_off % t;
723 sdiff_half_width = (off <= GUTTER_WIDTH_MINIMUM || w <= off
725 : MIN (off - GUTTER_WIDTH_MINIMUM, w - off));
726 sdiff_column2_offset = sdiff_half_width ? off : w;
729 /* Make the horizon at least as large as the context, so that
730 shift_boundaries has more freedom to shift the first and last hunks. */
731 if (horizon_lines < context)
732 horizon_lines = context;
734 summarize_regexp_list (&function_regexp_list);
735 summarize_regexp_list (&ignore_regexp_list);
737 if (output_style == OUTPUT_IFDEF)
739 for (i = 0; i < sizeof line_format / sizeof line_format[0]; i++)
741 line_format[i] = "%l\n";
742 if (!group_format[OLD])
744 = group_format[CHANGED] ? group_format[CHANGED] : "%<";
745 if (!group_format[NEW])
747 = group_format[CHANGED] ? group_format[CHANGED] : "%>";
748 if (!group_format[UNCHANGED])
749 group_format[UNCHANGED] = "%=";
750 if (!group_format[CHANGED])
751 group_format[CHANGED] = concat (group_format[OLD],
752 group_format[NEW], "");
755 no_diff_means_no_output =
756 (output_style == OUTPUT_IFDEF ?
757 (!*group_format[UNCHANGED]
758 || (STREQ (group_format[UNCHANGED], "%=")
759 && !*line_format[UNCHANGED]))
760 : (output_style != OUTPUT_SDIFF) | suppress_common_lines);
762 files_can_be_treated_as_binary =
764 & ~ (ignore_blank_lines | ignore_case | strip_trailing_cr
765 | (ignore_regexp_list.regexps || ignore_white_space)));
767 switch_string = option_list (argv + 1, optind - 1);
772 fatal ("--from-file and --to-file both specified");
774 for (; optind < argc; optind++)
776 int status = compare_files (NULL, from_file, argv[optind]);
777 if (exit_status < status)
778 exit_status = status;
784 for (; optind < argc; optind++)
786 int status = compare_files (NULL, argv[optind], to_file);
787 if (exit_status < status)
788 exit_status = status;
792 if (argc - optind != 2)
794 if (argc - optind < 2)
795 try_help ("missing operand after '%s'", argv[argc - 1]);
797 try_help ("extra operand '%s'", argv[optind + 2]);
800 exit_status = compare_files (NULL, argv[optind], argv[optind + 1]);
804 /* Print any messages that were saved up for last. */
805 print_message_queue ();
812 /* Append to REGLIST the regexp PATTERN. */
815 add_regexp (struct regexp_list *reglist, char const *pattern)
817 size_t patlen = strlen (pattern);
818 char const *m = re_compile_pattern (pattern, patlen, reglist->buf);
821 error (EXIT_TROUBLE, 0, "%s: %s", pattern, m);
824 char *regexps = reglist->regexps;
825 size_t len = reglist->len;
826 bool multiple_regexps = reglist->multiple_regexps = regexps != 0;
827 size_t newlen = reglist->len = len + 2 * multiple_regexps + patlen;
828 size_t size = reglist->size;
836 while (size <= newlen);
838 reglist->size = size;
839 reglist->regexps = regexps = xrealloc (regexps, size);
841 if (multiple_regexps)
843 regexps[len++] = '\\';
844 regexps[len++] = '|';
846 memcpy (regexps + len, pattern, patlen + 1);
850 /* Ensure that REGLIST represents the disjunction of its regexps.
851 This is done here, rather than earlier, to avoid O(N^2) behavior. */
854 summarize_regexp_list (struct regexp_list *reglist)
856 if (reglist->regexps)
858 /* At least one regexp was specified. Allocate a fastmap for it. */
859 reglist->buf->fastmap = xmalloc (1 << CHAR_BIT);
860 if (reglist->multiple_regexps)
862 /* Compile the disjunction of the regexps.
863 (If just one regexp was specified, it is already compiled.) */
864 char const *m = re_compile_pattern (reglist->regexps, reglist->len,
867 die (EXIT_TROUBLE, 0, "%s: %s", reglist->regexps, m);
873 try_help (char const *reason_msgid, char const *operand)
876 error (0, 0, _(reason_msgid), operand);
877 die (EXIT_TROUBLE, 0, _("Try '%s --help' for more information."),
885 fatal ("write failed");
886 else if (fclose (stdout) != 0)
887 pfatal_with_name (_("standard output"));
890 static char const * const option_help_msgid[] = {
891 N_(" --normal output a normal diff (the default)"),
892 N_("-q, --brief report only when files differ"),
893 N_("-s, --report-identical-files report when two files are the same"),
894 N_("-c, -C NUM, --context[=NUM] output NUM (default 3) lines of copied context"),
895 N_("-u, -U NUM, --unified[=NUM] output NUM (default 3) lines of unified context"),
896 N_("-e, --ed output an ed script"),
897 N_("-n, --rcs output an RCS format diff"),
898 N_("-y, --side-by-side output in two columns"),
899 N_("-W, --width=NUM output at most NUM (default 130) print columns"),
900 N_(" --left-column output only the left column of common lines"),
901 N_(" --suppress-common-lines do not output common lines"),
903 N_("-p, --show-c-function show which C function each change is in"),
904 N_("-F, --show-function-line=RE show the most recent line matching RE"),
905 N_(" --label LABEL use LABEL instead of file name and timestamp\n"
906 " (can be repeated)"),
908 N_("-t, --expand-tabs expand tabs to spaces in output"),
909 N_("-T, --initial-tab make tabs line up by prepending a tab"),
910 N_(" --tabsize=NUM tab stops every NUM (default 8) print columns"),
911 N_(" --suppress-blank-empty suppress space or tab before empty output lines"),
912 N_("-l, --paginate pass output through 'pr' to paginate it"),
914 N_("-r, --recursive recursively compare any subdirectories found"),
915 N_(" --no-dereference don't follow symbolic links"),
916 N_("-N, --new-file treat absent files as empty"),
917 N_(" --unidirectional-new-file treat absent first files as empty"),
918 N_(" --ignore-file-name-case ignore case when comparing file names"),
919 N_(" --no-ignore-file-name-case consider case when comparing file names"),
920 N_("-x, --exclude=PAT exclude files that match PAT"),
921 N_("-X, --exclude-from=FILE exclude files that match any pattern in FILE"),
922 N_("-S, --starting-file=FILE start with FILE when comparing directories"),
923 N_(" --from-file=FILE1 compare FILE1 to all operands;\n"
924 " FILE1 can be a directory"),
925 N_(" --to-file=FILE2 compare all operands to FILE2;\n"
926 " FILE2 can be a directory"),
928 N_("-i, --ignore-case ignore case differences in file contents"),
929 N_("-E, --ignore-tab-expansion ignore changes due to tab expansion"),
930 N_("-Z, --ignore-trailing-space ignore white space at line end"),
931 N_("-b, --ignore-space-change ignore changes in the amount of white space"),
932 N_("-w, --ignore-all-space ignore all white space"),
933 N_("-B, --ignore-blank-lines ignore changes where lines are all blank"),
934 N_("-I, --ignore-matching-lines=RE ignore changes where all lines match RE"),
936 N_("-a, --text treat all files as text"),
937 N_(" --strip-trailing-cr strip trailing carriage return on input"),
939 N_(" --binary read and write data in binary mode"),
942 N_("-D, --ifdef=NAME output merged file with '#ifdef NAME' diffs"),
943 N_(" --GTYPE-group-format=GFMT format GTYPE input groups with GFMT"),
944 N_(" --line-format=LFMT format all input lines with LFMT"),
945 N_(" --LTYPE-line-format=LFMT format LTYPE input lines with LFMT"),
946 N_(" These format options provide fine-grained control over the output\n"
947 " of diff, generalizing -D/--ifdef."),
948 N_(" LTYPE is 'old', 'new', or 'unchanged'. GTYPE is LTYPE or 'changed'."),
949 N_(" GFMT (only) may contain:\n\
950 %< lines from FILE1\n\
951 %> lines from FILE2\n\
952 %= lines common to FILE1 and FILE2\n\
953 %[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER\n\
954 LETTERs are as follows for new group, lower case for old group:\n\
955 F first line number\n\
956 L last line number\n\
957 N number of lines = L-F+1\n\
960 %(A=B?T:E) if A equals B then T else E"),
961 N_(" LFMT (only) may contain:\n\
962 %L contents of line\n\
963 %l contents of line, excluding any trailing newline\n\
964 %[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number"),
965 N_(" Both GFMT and LFMT may contain:\n\
967 %c'C' the single character C\n\
968 %c'\\OOO' the character with octal code OOO\n\
969 C the character C (other characters represent themselves)"),
971 N_("-d, --minimal try hard to find a smaller set of changes"),
972 N_(" --horizon-lines=NUM keep NUM lines of the common prefix and suffix"),
973 N_(" --speed-large-files assume large files and many scattered small changes"),
974 N_(" --color[=WHEN] colorize the output; WHEN can be 'never', 'always',\n"
975 " or 'auto' (the default)"),
976 N_(" --palette=PALETTE the colors to use when --color is active; PALETTE is\n"
977 " a colon-separated list of terminfo capabilities"),
979 N_(" --help display this help and exit"),
980 N_("-v, --version output version information and exit"),
982 N_("FILES are 'FILE1 FILE2' or 'DIR1 DIR2' or 'DIR FILE' or 'FILE DIR'."),
983 N_("If --from-file or --to-file is given, there are no restrictions on FILE(s)."),
984 N_("If a FILE is '-', read standard input."),
985 N_("Exit status is 0 if inputs are the same, 1 if different, 2 if trouble."),
992 char const * const *p;
994 printf (_("Usage: %s [OPTION]... FILES\n"), program_name);
995 printf ("%s\n\n", _("Compare FILES line by line."));
998 Mandatory arguments to long options are mandatory for short options too.\n\
1001 for (p = option_help_msgid; *p; p++)
1007 char const *msg = _(*p);
1009 while ((nl = strchr (msg, '\n')))
1011 int msglen = nl + 1 - msg;
1012 /* This assertion is solely to avoid a warning from
1013 gcc's -Wformat-overflow=. */
1014 assert (msglen < 4096);
1015 printf (" %.*s", msglen, msg);
1019 printf (" %s\n" + 2 * (*msg != ' ' && *msg != '-'), msg);
1022 emit_bug_reporting_address ();
1025 /* Set VAR to VALUE, reporting an OPTION error if this is a
1028 specify_value (char const **var, char const *value, char const *option)
1030 if (*var && ! STREQ (*var, value))
1032 error (0, 0, _("conflicting %s option value '%s'"), option, value);
1033 try_help (NULL, NULL);
1038 /* Set the output style to STYLE, diagnosing conflicts. */
1040 specify_style (enum output_style style)
1042 if (output_style != style)
1044 if (output_style != OUTPUT_UNSPECIFIED)
1045 try_help ("conflicting output style options", NULL);
1046 output_style = style;
1050 /* Set the color mode. */
1052 specify_colors_style (char const *value)
1054 if (value == NULL || STREQ (value, "auto"))
1055 colors_style = AUTO;
1056 else if (STREQ (value, "always"))
1057 colors_style = ALWAYS;
1058 else if (STREQ (value, "never"))
1059 colors_style = NEVER;
1061 try_help ("invalid color '%s'", value);
1065 /* Set the last-modified time of *ST to be the current time. */
1068 set_mtime_to_now (struct stat *st)
1070 #ifdef STAT_TIMESPEC
1071 gettime (&STAT_TIMESPEC (st, st_mtim));
1075 st->st_mtime = t.tv_sec;
1076 # if defined STAT_TIMESPEC_NS
1077 STAT_TIMESPEC_NS (st, st_mtim) = t.tv_nsec;
1078 # elif defined HAVE_STRUCT_STAT_ST_SPARE1
1079 st->st_spare1 = t.tv_nsec / 1000;
1084 /* Compare two files (or dirs) with parent comparison PARENT
1085 and names NAME0 and NAME1.
1086 (If PARENT is null, then the first name is just NAME0, etc.)
1087 This is self-contained; it opens the files and closes them.
1089 Value is EXIT_SUCCESS if files are the same, EXIT_FAILURE if
1090 different, EXIT_TROUBLE if there is a problem opening them. */
1093 compare_files (struct comparison const *parent,
1097 struct comparison cmp;
1098 #define DIR_P(f) (S_ISDIR (cmp.file[f].stat.st_mode) != 0)
1100 int status = EXIT_SUCCESS;
1105 /* If this is directory comparison, perhaps we have a file
1106 that exists only in one of the directories.
1107 If so, just print a message to that effect. */
1109 if (! ((name0 && name1)
1110 || (unidirectional_new_file && name1)
1113 char const *name = name0 ? name0 : name1;
1114 char const *dir = parent->file[!name0].name;
1116 /* See POSIX 1003.1-2001 for this format. */
1117 message ("Only in %s: %s\n", dir, name);
1119 /* Return EXIT_FAILURE so that diff_dirs will return
1120 EXIT_FAILURE ("some files differ"). */
1121 return EXIT_FAILURE;
1124 memset (cmp.file, 0, sizeof cmp.file);
1125 cmp.parent = parent;
1127 /* cmp.file[f].desc markers */
1128 #define NONEXISTENT (-1) /* nonexistent file */
1129 #define UNOPENED (-2) /* unopened file (e.g. directory) */
1130 #define ERRNO_ENCODE(errno) (-3 - (errno)) /* encoded errno value */
1132 #define ERRNO_DECODE(desc) (-3 - (desc)) /* inverse of ERRNO_ENCODE */
1134 cmp.file[0].desc = name0 ? UNOPENED : NONEXISTENT;
1135 cmp.file[1].desc = name1 ? UNOPENED : NONEXISTENT;
1137 /* Now record the full name of each file, including nonexistent ones. */
1148 cmp.file[0].name = name0;
1149 cmp.file[1].name = name1;
1153 cmp.file[0].name = free0
1154 = file_name_concat (parent->file[0].name, name0, NULL);
1155 cmp.file[1].name = free1
1156 = file_name_concat (parent->file[1].name, name1, NULL);
1159 /* Stat the files. */
1161 for (f = 0; f < 2; f++)
1163 if (cmp.file[f].desc != NONEXISTENT)
1165 if (f && file_name_cmp (cmp.file[f].name, cmp.file[0].name) == 0)
1167 cmp.file[f].desc = cmp.file[0].desc;
1168 cmp.file[f].stat = cmp.file[0].stat;
1170 else if (STREQ (cmp.file[f].name, "-"))
1172 cmp.file[f].desc = STDIN_FILENO;
1173 if (binary && ! isatty (STDIN_FILENO))
1174 set_binary_mode (STDIN_FILENO, O_BINARY);
1175 if (fstat (STDIN_FILENO, &cmp.file[f].stat) != 0)
1176 cmp.file[f].desc = ERRNO_ENCODE (errno);
1179 if (S_ISREG (cmp.file[f].stat.st_mode))
1181 off_t pos = lseek (STDIN_FILENO, 0, SEEK_CUR);
1183 cmp.file[f].desc = ERRNO_ENCODE (errno);
1185 cmp.file[f].stat.st_size =
1186 MAX (0, cmp.file[f].stat.st_size - pos);
1189 /* POSIX 1003.1-2001 requires current time for
1191 set_mtime_to_now (&cmp.file[f].stat);
1194 else if ((no_dereference_symlinks
1195 ? lstat (cmp.file[f].name, &cmp.file[f].stat)
1196 : stat (cmp.file[f].name, &cmp.file[f].stat))
1198 cmp.file[f].desc = ERRNO_ENCODE (errno);
1202 /* Mark files as nonexistent as needed for -N and -P, if they are
1203 inaccessible empty regular files (the kind of files that 'patch'
1204 creates to indicate nonexistent backups), or if they are
1205 top-level files that do not exist but their counterparts do
1207 for (f = 0; f < 2; f++)
1208 if ((new_file || (f == 0 && unidirectional_new_file))
1209 && (cmp.file[f].desc == UNOPENED
1210 ? (S_ISREG (cmp.file[f].stat.st_mode)
1211 && ! (cmp.file[f].stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO))
1212 && cmp.file[f].stat.st_size == 0)
1213 : ((cmp.file[f].desc == ERRNO_ENCODE (ENOENT)
1214 || cmp.file[f].desc == ERRNO_ENCODE (EBADF))
1216 && (cmp.file[1 - f].desc == UNOPENED
1217 || cmp.file[1 - f].desc == STDIN_FILENO))))
1218 cmp.file[f].desc = NONEXISTENT;
1220 for (f = 0; f < 2; f++)
1221 if (cmp.file[f].desc == NONEXISTENT)
1223 memset (&cmp.file[f].stat, 0, sizeof cmp.file[f].stat);
1224 cmp.file[f].stat.st_mode = cmp.file[1 - f].stat.st_mode;
1227 for (f = 0; f < 2; f++)
1229 int e = ERRNO_DECODE (cmp.file[f].desc);
1233 perror_with_name (cmp.file[f].name);
1234 status = EXIT_TROUBLE;
1238 if (status == EXIT_SUCCESS && ! parent && DIR_P (0) != DIR_P (1))
1240 /* If one is a directory, and it was specified in the command line,
1241 use the file in that dir with the other file's basename. */
1243 int fnm_arg = DIR_P (0);
1244 int dir_arg = 1 - fnm_arg;
1245 char const *fnm = cmp.file[fnm_arg].name;
1246 char const *dir = cmp.file[dir_arg].name;
1247 char const *filename = cmp.file[dir_arg].name = free0
1248 = find_dir_file_pathname (dir, last_component (fnm));
1250 if (STREQ (fnm, "-"))
1251 fatal ("cannot compare '-' to a directory");
1253 if ((no_dereference_symlinks
1254 ? lstat (filename, &cmp.file[dir_arg].stat)
1255 : stat (filename, &cmp.file[dir_arg].stat))
1258 perror_with_name (filename);
1259 status = EXIT_TROUBLE;
1263 if (status != EXIT_SUCCESS)
1265 /* One of the files should exist but does not. */
1267 else if (cmp.file[0].desc == NONEXISTENT
1268 && cmp.file[1].desc == NONEXISTENT)
1270 /* Neither file "exists", so there's nothing to compare. */
1272 else if ((same_files
1273 = (cmp.file[0].desc != NONEXISTENT
1274 && cmp.file[1].desc != NONEXISTENT
1275 && 0 < same_file (&cmp.file[0].stat, &cmp.file[1].stat)
1276 && same_file_attributes (&cmp.file[0].stat,
1277 &cmp.file[1].stat)))
1278 && no_diff_means_no_output)
1280 /* The two named files are actually the same physical file.
1281 We know they are identical without actually reading them. */
1283 else if (DIR_P (0) & DIR_P (1))
1285 if (output_style == OUTPUT_IFDEF)
1286 fatal ("-D option not supported with directories");
1288 /* If both are directories, compare the files in them. */
1290 if (parent && !recursive)
1292 /* But don't compare dir contents one level down
1293 unless -r was specified.
1294 See POSIX 1003.1-2001 for this format. */
1295 message ("Common subdirectories: %s and %s\n",
1296 cmp.file[0].name, cmp.file[1].name);
1299 status = diff_dirs (&cmp, compare_files);
1301 else if ((DIR_P (0) | DIR_P (1))
1303 && !((S_ISREG (cmp.file[0].stat.st_mode)
1304 || S_ISLNK (cmp.file[0].stat.st_mode))
1305 && (S_ISREG (cmp.file[1].stat.st_mode)
1306 || S_ISLNK (cmp.file[1].stat.st_mode)))))
1308 if (cmp.file[0].desc == NONEXISTENT || cmp.file[1].desc == NONEXISTENT)
1310 /* We have a subdirectory that exists only in one directory. */
1312 if ((DIR_P (0) | DIR_P (1))
1315 || (unidirectional_new_file
1316 && cmp.file[0].desc == NONEXISTENT)))
1317 status = diff_dirs (&cmp, compare_files);
1322 /* PARENT must be non-NULL here. */
1324 dir = parent->file[cmp.file[0].desc == NONEXISTENT].name;
1326 /* See POSIX 1003.1-2001 for this format. */
1327 message ("Only in %s: %s\n", dir, name0);
1329 status = EXIT_FAILURE;
1334 /* We have two files that are not to be compared. */
1336 /* See POSIX 1003.1-2001 for this format. */
1337 message5 ("File %s is a %s while file %s is a %s\n",
1338 file_label[0] ? file_label[0] : cmp.file[0].name,
1339 file_type (&cmp.file[0].stat),
1340 file_label[1] ? file_label[1] : cmp.file[1].name,
1341 file_type (&cmp.file[1].stat));
1343 /* This is a difference. */
1344 status = EXIT_FAILURE;
1347 else if (S_ISLNK (cmp.file[0].stat.st_mode)
1348 || S_ISLNK (cmp.file[1].stat.st_mode))
1350 /* We get here only if we use lstat(), not stat(). */
1351 assert (no_dereference_symlinks);
1353 if (S_ISLNK (cmp.file[0].stat.st_mode)
1354 && S_ISLNK (cmp.file[1].stat.st_mode))
1356 /* Compare the values of the symbolic links. */
1357 char *link_value[2] = { NULL, NULL };
1359 for (f = 0; f < 2; f++)
1361 link_value[f] = xreadlink (cmp.file[f].name);
1362 if (link_value[f] == NULL)
1364 perror_with_name (cmp.file[f].name);
1365 status = EXIT_TROUBLE;
1369 if (status == EXIT_SUCCESS)
1371 if ( ! STREQ (link_value[0], link_value[1]))
1373 message ("Symbolic links %s and %s differ\n",
1374 cmp.file[0].name, cmp.file[1].name);
1375 /* This is a difference. */
1376 status = EXIT_FAILURE;
1379 for (f = 0; f < 2; f++)
1380 free (link_value[f]);
1384 /* We have two files that are not to be compared, because
1385 one of them is a symbolic link and the other one is not. */
1387 message5 ("File %s is a %s while file %s is a %s\n",
1388 file_label[0] ? file_label[0] : cmp.file[0].name,
1389 file_type (&cmp.file[0].stat),
1390 file_label[1] ? file_label[1] : cmp.file[1].name,
1391 file_type (&cmp.file[1].stat));
1393 /* This is a difference. */
1394 status = EXIT_FAILURE;
1397 else if (files_can_be_treated_as_binary
1398 && S_ISREG (cmp.file[0].stat.st_mode)
1399 && S_ISREG (cmp.file[1].stat.st_mode)
1400 && cmp.file[0].stat.st_size != cmp.file[1].stat.st_size
1401 && 0 < cmp.file[0].stat.st_size
1402 && 0 < cmp.file[1].stat.st_size)
1404 message ("Files %s and %s differ\n",
1405 file_label[0] ? file_label[0] : cmp.file[0].name,
1406 file_label[1] ? file_label[1] : cmp.file[1].name);
1407 status = EXIT_FAILURE;
1411 /* Both exist and neither is a directory. */
1413 /* Open the files and record their descriptors. */
1415 int oflags = O_RDONLY | (binary ? O_BINARY : 0);
1417 if (cmp.file[0].desc == UNOPENED)
1418 if ((cmp.file[0].desc = open (cmp.file[0].name, oflags, 0)) < 0)
1420 perror_with_name (cmp.file[0].name);
1421 status = EXIT_TROUBLE;
1423 if (cmp.file[1].desc == UNOPENED)
1426 cmp.file[1].desc = cmp.file[0].desc;
1427 else if ((cmp.file[1].desc = open (cmp.file[1].name, oflags, 0)) < 0)
1429 perror_with_name (cmp.file[1].name);
1430 status = EXIT_TROUBLE;
1434 /* Compare the files, if no error was found. */
1436 if (status == EXIT_SUCCESS)
1437 status = diff_2_files (&cmp);
1439 /* Close the file descriptors. */
1441 if (0 <= cmp.file[0].desc && close (cmp.file[0].desc) != 0)
1443 perror_with_name (cmp.file[0].name);
1444 status = EXIT_TROUBLE;
1446 if (0 <= cmp.file[1].desc && cmp.file[0].desc != cmp.file[1].desc
1447 && close (cmp.file[1].desc) != 0)
1449 perror_with_name (cmp.file[1].name);
1450 status = EXIT_TROUBLE;
1454 /* Now the comparison has been done, if no error prevented it,
1455 and STATUS is the value this function will return. */
1457 if (status == EXIT_SUCCESS)
1459 if (report_identical_files && !DIR_P (0))
1460 message ("Files %s and %s are identical\n",
1461 file_label[0] ? file_label[0] : cmp.file[0].name,
1462 file_label[1] ? file_label[1] : cmp.file[1].name);
1466 /* Flush stdout so that the user sees differences immediately.
1467 This can hurt performance, unfortunately. */
1468 if (fflush (stdout) != 0)
1469 pfatal_with_name (_("standard output"));