1 /* diff - compare files line by line
3 Copyright (C) 1988-1989, 1992-1994, 1996, 1998, 2001-2002, 2004, 2006-2007,
4 2009-2013 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/>. */
30 #include <filenamecat.h>
31 #include <file-type.h>
34 #include <hard-locale.h>
38 #include <stat-time.h>
40 #include <version-etc.h>
42 #include <xreadlink.h>
43 #include <binary-io.h>
45 /* The official name of this program (e.g., no 'g' prefix). */
46 #define PROGRAM_NAME "diff"
49 proper_name ("Paul Eggert"), \
50 proper_name ("Mike Haertel"), \
51 proper_name ("David Hayes"), \
52 proper_name ("Richard Stallman"), \
53 proper_name ("Len Tower")
55 #ifndef GUTTER_WIDTH_MINIMUM
56 # define GUTTER_WIDTH_MINIMUM 3
61 char *regexps; /* chars representing disjunction of the regexps */
62 size_t len; /* chars used in 'regexps' */
63 size_t size; /* size malloc'ed for 'regexps'; 0 if not malloc'ed */
64 bool multiple_regexps;/* Does 'regexps' represent a disjunction? */
65 struct re_pattern_buffer *buf;
68 static int compare_files (struct comparison const *, char const *, char const *);
69 static void add_regexp (struct regexp_list *, char const *);
70 static void summarize_regexp_list (struct regexp_list *);
71 static void specify_style (enum output_style);
72 static void specify_value (char const **, char const *, char const *);
73 static void try_help (char const *, char const *) __attribute__((noreturn));
74 static void check_stdout (void);
75 static void usage (void);
77 /* If comparing directories, compare their common subdirectories
79 static bool recursive;
81 /* In context diffs, show previous lines that match these regexps. */
82 static struct regexp_list function_regexp_list;
84 /* Ignore changes affecting only lines that match these regexps. */
85 static struct regexp_list ignore_regexp_list;
88 /* Use binary I/O when reading and writing data (--binary).
89 On POSIX hosts, this has no effect. */
92 enum { binary = true };
95 /* If one file is missing, treat it as present but empty (-N). */
98 /* If the first file is missing, treat it as present but empty
99 (--unidirectional-new-file). */
100 static bool unidirectional_new_file;
102 /* Report files compared that are the same (-s).
103 Normally nothing is output when that happens. */
104 static bool report_identical_files;
106 static char const shortopts[] =
107 "0123456789abBcC:dD:eEfF:hHiI:lL:nNpPqrsS:tTuU:vwW:x:X:yZ";
109 /* Values for long options that do not have single-letter equivalents. */
112 BINARY_OPTION = CHAR_MAX + 1,
115 HORIZON_LINES_OPTION,
116 IGNORE_FILE_NAME_CASE_OPTION,
117 INHIBIT_HUNK_MERGE_OPTION,
120 NO_DEREFERENCE_OPTION,
121 NO_IGNORE_FILE_NAME_CASE_OPTION,
123 SDIFF_MERGE_ASSIST_OPTION,
124 STRIP_TRAILING_CR_OPTION,
125 SUPPRESS_BLANK_EMPTY_OPTION,
126 SUPPRESS_COMMON_LINES_OPTION,
130 /* These options must be in sequence. */
131 UNCHANGED_LINE_FORMAT_OPTION,
132 OLD_LINE_FORMAT_OPTION,
133 NEW_LINE_FORMAT_OPTION,
135 /* These options must be in sequence. */
136 UNCHANGED_GROUP_FORMAT_OPTION,
137 OLD_GROUP_FORMAT_OPTION,
138 NEW_GROUP_FORMAT_OPTION,
139 CHANGED_GROUP_FORMAT_OPTION
142 static char const group_format_option[][sizeof "--unchanged-group-format"] =
144 "--unchanged-group-format",
145 "--old-group-format",
146 "--new-group-format",
147 "--changed-group-format"
150 static char const line_format_option[][sizeof "--unchanged-line-format"] =
152 "--unchanged-line-format",
157 static struct option const longopts[] =
159 {"binary", 0, 0, BINARY_OPTION},
160 {"brief", 0, 0, 'q'},
161 {"changed-group-format", 1, 0, CHANGED_GROUP_FORMAT_OPTION},
162 {"context", 2, 0, 'C'},
164 {"exclude", 1, 0, 'x'},
165 {"exclude-from", 1, 0, 'X'},
166 {"expand-tabs", 0, 0, 't'},
167 {"forward-ed", 0, 0, 'f'},
168 {"from-file", 1, 0, FROM_FILE_OPTION},
169 {"help", 0, 0, HELP_OPTION},
170 {"horizon-lines", 1, 0, HORIZON_LINES_OPTION},
171 {"ifdef", 1, 0, 'D'},
172 {"ignore-all-space", 0, 0, 'w'},
173 {"ignore-blank-lines", 0, 0, 'B'},
174 {"ignore-case", 0, 0, 'i'},
175 {"ignore-file-name-case", 0, 0, IGNORE_FILE_NAME_CASE_OPTION},
176 {"ignore-matching-lines", 1, 0, 'I'},
177 {"ignore-space-change", 0, 0, 'b'},
178 {"ignore-tab-expansion", 0, 0, 'E'},
179 {"ignore-trailing-space", 0, 0, 'Z'},
180 {"inhibit-hunk-merge", 0, 0, INHIBIT_HUNK_MERGE_OPTION},
181 {"initial-tab", 0, 0, 'T'},
182 {"label", 1, 0, 'L'},
183 {"left-column", 0, 0, LEFT_COLUMN_OPTION},
184 {"line-format", 1, 0, LINE_FORMAT_OPTION},
185 {"minimal", 0, 0, 'd'},
186 {"new-file", 0, 0, 'N'},
187 {"new-group-format", 1, 0, NEW_GROUP_FORMAT_OPTION},
188 {"new-line-format", 1, 0, NEW_LINE_FORMAT_OPTION},
189 {"no-dereference", 0, 0, NO_DEREFERENCE_OPTION},
190 {"no-ignore-file-name-case", 0, 0, NO_IGNORE_FILE_NAME_CASE_OPTION},
191 {"normal", 0, 0, NORMAL_OPTION},
192 {"old-group-format", 1, 0, OLD_GROUP_FORMAT_OPTION},
193 {"old-line-format", 1, 0, OLD_LINE_FORMAT_OPTION},
194 {"paginate", 0, 0, 'l'},
196 {"recursive", 0, 0, 'r'},
197 {"report-identical-files", 0, 0, 's'},
198 {"sdiff-merge-assist", 0, 0, SDIFF_MERGE_ASSIST_OPTION},
199 {"show-c-function", 0, 0, 'p'},
200 {"show-function-line", 1, 0, 'F'},
201 {"side-by-side", 0, 0, 'y'},
202 {"speed-large-files", 0, 0, 'H'},
203 {"starting-file", 1, 0, 'S'},
204 {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},
205 {"suppress-blank-empty", 0, 0, SUPPRESS_BLANK_EMPTY_OPTION},
206 {"suppress-common-lines", 0, 0, SUPPRESS_COMMON_LINES_OPTION},
207 {"tabsize", 1, 0, TABSIZE_OPTION},
209 {"to-file", 1, 0, TO_FILE_OPTION},
210 {"unchanged-group-format", 1, 0, UNCHANGED_GROUP_FORMAT_OPTION},
211 {"unchanged-line-format", 1, 0, UNCHANGED_LINE_FORMAT_OPTION},
212 {"unidirectional-new-file", 0, 0, 'P'},
213 {"unified", 2, 0, 'U'},
214 {"version", 0, 0, 'v'},
215 {"width", 1, 0, 'W'},
219 /* Return a string containing the command options with which diff was invoked.
220 Spaces appear between what were separate ARGV-elements.
221 There is a space at the beginning but none at the end.
222 If there were no options, the result is an empty string.
224 Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT,
225 the length of that vector. */
228 option_list (char **optionvec, int count)
235 for (i = 0; i < count; i++)
236 size += 1 + shell_quote_length (optionvec[i]);
238 p = result = xmalloc (size);
240 for (i = 0; i < count; i++)
243 p = shell_quote_copy (p, optionvec[i]);
251 /* Return an option value suitable for add_exclude. */
254 exclude_options (void)
256 return EXCLUDE_WILDCARDS | (ignore_file_name_case ? FNM_CASEFOLD : 0);
260 main (int argc, char **argv)
262 int exit_status = EXIT_SUCCESS;
267 bool explicit_context = false;
269 bool show_c_function = false;
270 char const *from_file = NULL;
271 char const *to_file = NULL;
275 /* Do our initializations. */
276 exit_failure = EXIT_TROUBLE;
277 initialize_main (&argc, &argv);
278 set_program_name (argv[0]);
279 setlocale (LC_ALL, "");
280 bindtextdomain (PACKAGE, LOCALEDIR);
281 textdomain (PACKAGE);
283 function_regexp_list.buf = &function_regexp;
284 ignore_regexp_list.buf = &ignore_regexp;
285 re_set_syntax (RE_SYNTAX_GREP | RE_NO_POSIX_BACKTRACKING);
286 excluded = new_exclude ();
288 /* Decode the options. */
290 while ((c = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
307 if (! ISDIGIT (prev))
309 else if (LIN_MAX / 10 < ocontext
310 || ((ocontext = 10 * ocontext + c - '0') < 0))
319 if (ignore_white_space < IGNORE_SPACE_CHANGE)
320 ignore_white_space = IGNORE_SPACE_CHANGE;
324 if (ignore_white_space < IGNORE_SPACE_CHANGE)
325 ignore_white_space |= IGNORE_TRAILING_SPACE;
329 ignore_blank_lines = true;
337 numval = strtoumax (optarg, &numend, 10);
339 try_help ("invalid context length '%s'", optarg);
340 if (LIN_MAX < numval)
346 specify_style (c == 'U' ? OUTPUT_UNIFIED : OUTPUT_CONTEXT);
347 if (context < numval)
349 explicit_context = true;
354 specify_style (OUTPUT_CONTEXT);
364 specify_style (OUTPUT_IFDEF);
366 static char const C_ifdef_group_formats[] =
367 "%%=%c#ifndef %s\n%%<#endif /* ! %s */\n%c#ifdef %s\n%%>#endif /* %s */\n%c#ifndef %s\n%%<#else /* %s */\n%%>#endif /* %s */\n";
368 char *b = xmalloc (sizeof C_ifdef_group_formats
369 + 7 * strlen (optarg) - 14 /* 7*"%s" */
370 - 8 /* 5*"%%" + 3*"%c" */);
371 sprintf (b, C_ifdef_group_formats,
375 optarg, optarg, optarg);
376 for (i = 0; i < sizeof group_format / sizeof group_format[0]; i++)
378 specify_value (&group_format[i], b, "-D");
385 specify_style (OUTPUT_ED);
389 if (ignore_white_space < IGNORE_SPACE_CHANGE)
390 ignore_white_space |= IGNORE_TAB_EXPANSION;
394 specify_style (OUTPUT_FORWARD_ED);
398 add_regexp (&function_regexp_list, optarg);
402 /* Split the files into chunks for faster processing.
403 Usually does not change the result.
405 This currently has no effect. */
409 speed_large_files = true;
417 add_regexp (&ignore_regexp_list, optarg);
422 try_help ("pagination not supported on this host", NULL);
425 /* Pagination requires forking and waiting, and
426 System V fork+wait does not work if SIGCHLD is ignored. */
427 signal (SIGCHLD, SIG_DFL);
433 file_label[0] = optarg;
434 else if (!file_label[1])
435 file_label[1] = optarg;
437 fatal ("too many file label options");
441 specify_style (OUTPUT_RCS);
449 show_c_function = true;
450 add_regexp (&function_regexp_list, "^[[:alpha:]$_]");
454 unidirectional_new_file = true;
466 report_identical_files = true;
470 specify_value (&starting_file, optarg, "-S");
482 specify_style (OUTPUT_UNIFIED);
488 version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version,
489 AUTHORS, (char *) NULL);
494 ignore_white_space = IGNORE_ALL_SPACE;
498 add_exclude (excluded, optarg, exclude_options ());
502 if (add_exclude_file (add_exclude, excluded, optarg,
503 exclude_options (), '\n'))
504 pfatal_with_name (optarg);
508 specify_style (OUTPUT_SDIFF);
512 numval = strtoumax (optarg, &numend, 10);
513 if (! (0 < numval && numval <= SIZE_MAX) || *numend)
514 try_help ("invalid width '%s'", optarg);
518 fatal ("conflicting width options");
526 if (! isatty (STDOUT_FILENO))
527 set_binary_mode (STDOUT_FILENO, O_BINARY);
531 case FROM_FILE_OPTION:
532 specify_value (&from_file, optarg, "--from-file");
540 case HORIZON_LINES_OPTION:
541 numval = strtoumax (optarg, &numend, 10);
543 try_help ("invalid horizon length '%s'", optarg);
544 horizon_lines = MAX (horizon_lines, MIN (numval, LIN_MAX));
547 case IGNORE_FILE_NAME_CASE_OPTION:
548 ignore_file_name_case = true;
551 case INHIBIT_HUNK_MERGE_OPTION:
552 /* This option is obsolete, but accept it for backward
556 case LEFT_COLUMN_OPTION:
560 case LINE_FORMAT_OPTION:
561 specify_style (OUTPUT_IFDEF);
562 for (i = 0; i < sizeof line_format / sizeof line_format[0]; i++)
563 specify_value (&line_format[i], optarg, "--line-format");
566 case NO_DEREFERENCE_OPTION:
567 no_dereference_symlinks = true;
570 case NO_IGNORE_FILE_NAME_CASE_OPTION:
571 ignore_file_name_case = false;
575 specify_style (OUTPUT_NORMAL);
578 case SDIFF_MERGE_ASSIST_OPTION:
579 specify_style (OUTPUT_SDIFF);
580 sdiff_merge_assist = true;
583 case STRIP_TRAILING_CR_OPTION:
584 strip_trailing_cr = true;
587 case SUPPRESS_BLANK_EMPTY_OPTION:
588 suppress_blank_empty = true;
591 case SUPPRESS_COMMON_LINES_OPTION:
592 suppress_common_lines = true;
596 numval = strtoumax (optarg, &numend, 10);
597 if (! (0 < numval && numval <= SIZE_MAX) || *numend)
598 try_help ("invalid tabsize '%s'", optarg);
599 if (tabsize != numval)
602 fatal ("conflicting tabsize options");
608 specify_value (&to_file, optarg, "--to-file");
611 case UNCHANGED_LINE_FORMAT_OPTION:
612 case OLD_LINE_FORMAT_OPTION:
613 case NEW_LINE_FORMAT_OPTION:
614 specify_style (OUTPUT_IFDEF);
615 c -= UNCHANGED_LINE_FORMAT_OPTION;
616 specify_value (&line_format[c], optarg, line_format_option[c]);
619 case UNCHANGED_GROUP_FORMAT_OPTION:
620 case OLD_GROUP_FORMAT_OPTION:
621 case NEW_GROUP_FORMAT_OPTION:
622 case CHANGED_GROUP_FORMAT_OPTION:
623 specify_style (OUTPUT_IFDEF);
624 c -= UNCHANGED_GROUP_FORMAT_OPTION;
625 specify_value (&group_format[c], optarg, group_format_option[c]);
629 try_help (NULL, NULL);
634 if (output_style == OUTPUT_UNSPECIFIED)
638 specify_style (OUTPUT_CONTEXT);
643 specify_style (OUTPUT_NORMAL);
646 if (output_style != OUTPUT_CONTEXT || hard_locale (LC_TIME))
648 #if (defined STAT_TIMESPEC || defined STAT_TIMESPEC_NS \
649 || defined HAVE_STRUCT_STAT_ST_SPARE1)
650 time_format = "%Y-%m-%d %H:%M:%S.%N %z";
652 time_format = "%Y-%m-%d %H:%M:%S %z";
657 /* See POSIX 1003.1-2001 for this format. */
658 time_format = "%a %b %e %T %Y";
662 && (output_style == OUTPUT_CONTEXT
663 || output_style == OUTPUT_UNIFIED)
664 && (context < ocontext
665 || (ocontext < context && ! explicit_context)))
674 /* Maximize first the half line width, and then the gutter width,
675 according to the following constraints:
677 1. Two half lines plus a gutter must fit in a line.
678 2. If the half line width is nonzero:
679 a. The gutter width is at least GUTTER_WIDTH_MINIMUM.
680 b. If tabs are not expanded to spaces,
681 a half line plus a gutter is an integral number of tabs,
682 so that tabs in the right column line up. */
684 intmax_t t = expand_tabs ? 1 : tabsize;
686 intmax_t off = (w + t + GUTTER_WIDTH_MINIMUM) / (2 * t) * t;
687 sdiff_half_width = MAX (0, MIN (off - GUTTER_WIDTH_MINIMUM, w - off)),
688 sdiff_column2_offset = sdiff_half_width ? off : w;
691 /* Make the horizon at least as large as the context, so that
692 shift_boundaries has more freedom to shift the first and last hunks. */
693 if (horizon_lines < context)
694 horizon_lines = context;
696 summarize_regexp_list (&function_regexp_list);
697 summarize_regexp_list (&ignore_regexp_list);
699 if (output_style == OUTPUT_IFDEF)
701 for (i = 0; i < sizeof line_format / sizeof line_format[0]; i++)
703 line_format[i] = "%l\n";
704 if (!group_format[OLD])
706 = group_format[CHANGED] ? group_format[CHANGED] : "%<";
707 if (!group_format[NEW])
709 = group_format[CHANGED] ? group_format[CHANGED] : "%>";
710 if (!group_format[UNCHANGED])
711 group_format[UNCHANGED] = "%=";
712 if (!group_format[CHANGED])
713 group_format[CHANGED] = concat (group_format[OLD],
714 group_format[NEW], "");
717 no_diff_means_no_output =
718 (output_style == OUTPUT_IFDEF ?
719 (!*group_format[UNCHANGED]
720 || (STREQ (group_format[UNCHANGED], "%=")
721 && !*line_format[UNCHANGED]))
722 : (output_style != OUTPUT_SDIFF) | suppress_common_lines);
724 files_can_be_treated_as_binary =
726 & ~ (ignore_blank_lines | ignore_case | strip_trailing_cr
727 | (ignore_regexp_list.regexps || ignore_white_space)));
729 switch_string = option_list (argv + 1, optind - 1);
734 fatal ("--from-file and --to-file both specified");
736 for (; optind < argc; optind++)
738 int status = compare_files (NULL, from_file, argv[optind]);
739 if (exit_status < status)
740 exit_status = status;
746 for (; optind < argc; optind++)
748 int status = compare_files (NULL, argv[optind], to_file);
749 if (exit_status < status)
750 exit_status = status;
754 if (argc - optind != 2)
756 if (argc - optind < 2)
757 try_help ("missing operand after '%s'", argv[argc - 1]);
759 try_help ("extra operand '%s'", argv[optind + 2]);
762 exit_status = compare_files (NULL, argv[optind], argv[optind + 1]);
766 /* Print any messages that were saved up for last. */
767 print_message_queue ();
774 /* Append to REGLIST the regexp PATTERN. */
777 add_regexp (struct regexp_list *reglist, char const *pattern)
779 size_t patlen = strlen (pattern);
780 char const *m = re_compile_pattern (pattern, patlen, reglist->buf);
783 error (0, 0, "%s: %s", pattern, m);
786 char *regexps = reglist->regexps;
787 size_t len = reglist->len;
788 bool multiple_regexps = reglist->multiple_regexps = regexps != 0;
789 size_t newlen = reglist->len = len + 2 * multiple_regexps + patlen;
790 size_t size = reglist->size;
798 while (size <= newlen);
800 reglist->size = size;
801 reglist->regexps = regexps = xrealloc (regexps, size);
803 if (multiple_regexps)
805 regexps[len++] = '\\';
806 regexps[len++] = '|';
808 memcpy (regexps + len, pattern, patlen + 1);
812 /* Ensure that REGLIST represents the disjunction of its regexps.
813 This is done here, rather than earlier, to avoid O(N^2) behavior. */
816 summarize_regexp_list (struct regexp_list *reglist)
818 if (reglist->regexps)
820 /* At least one regexp was specified. Allocate a fastmap for it. */
821 reglist->buf->fastmap = xmalloc (1 << CHAR_BIT);
822 if (reglist->multiple_regexps)
824 /* Compile the disjunction of the regexps.
825 (If just one regexp was specified, it is already compiled.) */
826 char const *m = re_compile_pattern (reglist->regexps, reglist->len,
829 error (EXIT_TROUBLE, 0, "%s: %s", reglist->regexps, m);
835 try_help (char const *reason_msgid, char const *operand)
838 error (0, 0, _(reason_msgid), operand);
839 error (EXIT_TROUBLE, 0, _("Try '%s --help' for more information."),
848 fatal ("write failed");
849 else if (fclose (stdout) != 0)
850 pfatal_with_name (_("standard output"));
853 static char const * const option_help_msgid[] = {
854 N_(" --normal output a normal diff (the default)"),
855 N_("-q, --brief report only when files differ"),
856 N_("-s, --report-identical-files report when two files are the same"),
857 N_("-c, -C NUM, --context[=NUM] output NUM (default 3) lines of copied context"),
858 N_("-u, -U NUM, --unified[=NUM] output NUM (default 3) lines of unified context"),
859 N_("-e, --ed output an ed script"),
860 N_("-n, --rcs output an RCS format diff"),
861 N_("-y, --side-by-side output in two columns"),
862 N_("-W, --width=NUM output at most NUM (default 130) print columns"),
863 N_(" --left-column output only the left column of common lines"),
864 N_(" --suppress-common-lines do not output common lines"),
866 N_("-p, --show-c-function show which C function each change is in"),
867 N_("-F, --show-function-line=RE show the most recent line matching RE"),
868 N_(" --label LABEL use LABEL instead of file name\n"
869 " (can be repeated)"),
871 N_("-t, --expand-tabs expand tabs to spaces in output"),
872 N_("-T, --initial-tab make tabs line up by prepending a tab"),
873 N_(" --tabsize=NUM tab stops every NUM (default 8) print columns"),
874 N_(" --suppress-blank-empty suppress space or tab before empty output lines"),
875 N_("-l, --paginate pass output through 'pr' to paginate it"),
877 N_("-r, --recursive recursively compare any subdirectories found"),
878 N_(" --no-dereference don't follow symbolic links"),
879 N_("-N, --new-file treat absent files as empty"),
880 N_(" --unidirectional-new-file treat absent first files as empty"),
881 N_(" --ignore-file-name-case ignore case when comparing file names"),
882 N_(" --no-ignore-file-name-case consider case when comparing file names"),
883 N_("-x, --exclude=PAT exclude files that match PAT"),
884 N_("-X, --exclude-from=FILE exclude files that match any pattern in FILE"),
885 N_("-S, --starting-file=FILE start with FILE when comparing directories"),
886 N_(" --from-file=FILE1 compare FILE1 to all operands;\n"
887 " FILE1 can be a directory"),
888 N_(" --to-file=FILE2 compare all operands to FILE2;\n"
889 " FILE2 can be a directory"),
891 N_("-i, --ignore-case ignore case differences in file contents"),
892 N_("-E, --ignore-tab-expansion ignore changes due to tab expansion"),
893 N_("-Z, --ignore-trailing-space ignore white space at line end"),
894 N_("-b, --ignore-space-change ignore changes in the amount of white space"),
895 N_("-w, --ignore-all-space ignore all white space"),
896 N_("-B, --ignore-blank-lines ignore changes where lines are all blank"),
897 N_("-I, --ignore-matching-lines=RE ignore changes where all lines match RE"),
899 N_("-a, --text treat all files as text"),
900 N_(" --strip-trailing-cr strip trailing carriage return on input"),
902 N_(" --binary read and write data in binary mode"),
905 N_("-D, --ifdef=NAME output merged file with '#ifdef NAME' diffs"),
906 N_(" --GTYPE-group-format=GFMT format GTYPE input groups with GFMT"),
907 N_(" --line-format=LFMT format all input lines with LFMT"),
908 N_(" --LTYPE-line-format=LFMT format LTYPE input lines with LFMT"),
909 N_(" These format options provide fine-grained control over the output\n"
910 " of diff, generalizing -D/--ifdef."),
911 N_(" LTYPE is 'old', 'new', or 'unchanged'. GTYPE is LTYPE or 'changed'."),
912 N_(" GFMT (only) may contain:\n\
913 %< lines from FILE1\n\
914 %> lines from FILE2\n\
915 %= lines common to FILE1 and FILE2\n\
916 %[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER\n\
917 LETTERs are as follows for new group, lower case for old group:\n\
918 F first line number\n\
919 L last line number\n\
920 N number of lines = L-F+1\n\
923 %(A=B?T:E) if A equals B then T else E"),
924 N_(" LFMT (only) may contain:\n\
925 %L contents of line\n\
926 %l contents of line, excluding any trailing newline\n\
927 %[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number"),
928 N_(" Both GFMT and LFMT may contain:\n\
930 %c'C' the single character C\n\
931 %c'\\OOO' the character with octal code OOO\n\
932 C the character C (other characters represent themselves)"),
934 N_("-d, --minimal try hard to find a smaller set of changes"),
935 N_(" --horizon-lines=NUM keep NUM lines of the common prefix and suffix"),
936 N_(" --speed-large-files assume large files and many scattered small changes"),
938 N_(" --help display this help and exit"),
939 N_("-v, --version output version information and exit"),
941 N_("FILES are 'FILE1 FILE2' or 'DIR1 DIR2' or 'DIR FILE...' or 'FILE... DIR'."),
942 N_("If --from-file or --to-file is given, there are no restrictions on FILE(s)."),
943 N_("If a FILE is '-', read standard input."),
944 N_("Exit status is 0 if inputs are the same, 1 if different, 2 if trouble."),
951 char const * const *p;
953 printf (_("Usage: %s [OPTION]... FILES\n"), program_name);
954 printf ("%s\n\n", _("Compare FILES line by line."));
957 Mandatory arguments to long options are mandatory for short options too.\n\
960 for (p = option_help_msgid; *p; p++)
966 char const *msg = _(*p);
968 while ((nl = strchr (msg, '\n')))
970 int msglen = nl + 1 - msg;
971 printf (" %.*s", msglen, msg);
975 printf (" %s\n" + 2 * (*msg != ' ' && *msg != '-'), msg);
978 emit_bug_reporting_address ();
981 /* Set VAR to VALUE, reporting an OPTION error if this is a
984 specify_value (char const **var, char const *value, char const *option)
986 if (*var && ! STREQ (*var, value))
988 error (0, 0, _("conflicting %s option value '%s'"), option, value);
989 try_help (NULL, NULL);
994 /* Set the output style to STYLE, diagnosing conflicts. */
996 specify_style (enum output_style style)
998 if (output_style != style)
1000 if (output_style != OUTPUT_UNSPECIFIED)
1001 try_help ("conflicting output style options", NULL);
1002 output_style = style;
1006 /* Set the last-modified time of *ST to be the current time. */
1009 set_mtime_to_now (struct stat *st)
1011 #ifdef STAT_TIMESPEC
1012 gettime (&STAT_TIMESPEC (st, st_mtim));
1016 st->st_mtime = t.tv_sec;
1017 # if defined STAT_TIMESPEC_NS
1018 STAT_TIMESPEC_NS (st, st_mtim) = t.tv_nsec;
1019 # elif defined HAVE_STRUCT_STAT_ST_SPARE1
1020 st->st_spare1 = t.tv_nsec / 1000;
1025 /* Compare two files (or dirs) with parent comparison PARENT
1026 and names NAME0 and NAME1.
1027 (If PARENT is null, then the first name is just NAME0, etc.)
1028 This is self-contained; it opens the files and closes them.
1030 Value is EXIT_SUCCESS if files are the same, EXIT_FAILURE if
1031 different, EXIT_TROUBLE if there is a problem opening them. */
1034 compare_files (struct comparison const *parent,
1038 struct comparison cmp;
1039 #define DIR_P(f) (S_ISDIR (cmp.file[f].stat.st_mode) != 0)
1041 int status = EXIT_SUCCESS;
1046 /* If this is directory comparison, perhaps we have a file
1047 that exists only in one of the directories.
1048 If so, just print a message to that effect. */
1050 if (! ((name0 && name1)
1051 || (unidirectional_new_file && name1)
1054 char const *name = name0 ? name0 : name1;
1055 char const *dir = parent->file[!name0].name;
1057 /* See POSIX 1003.1-2001 for this format. */
1058 message ("Only in %s: %s\n", dir, name);
1060 /* Return EXIT_FAILURE so that diff_dirs will return
1061 EXIT_FAILURE ("some files differ"). */
1062 return EXIT_FAILURE;
1065 memset (cmp.file, 0, sizeof cmp.file);
1066 cmp.parent = parent;
1068 /* cmp.file[f].desc markers */
1069 #define NONEXISTENT (-1) /* nonexistent file */
1070 #define UNOPENED (-2) /* unopened file (e.g. directory) */
1071 #define ERRNO_ENCODE(errno) (-3 - (errno)) /* encoded errno value */
1073 #define ERRNO_DECODE(desc) (-3 - (desc)) /* inverse of ERRNO_ENCODE */
1075 cmp.file[0].desc = name0 ? UNOPENED : NONEXISTENT;
1076 cmp.file[1].desc = name1 ? UNOPENED : NONEXISTENT;
1078 /* Now record the full name of each file, including nonexistent ones. */
1089 cmp.file[0].name = name0;
1090 cmp.file[1].name = name1;
1094 cmp.file[0].name = free0
1095 = file_name_concat (parent->file[0].name, name0, NULL);
1096 cmp.file[1].name = free1
1097 = file_name_concat (parent->file[1].name, name1, NULL);
1100 /* Stat the files. */
1102 for (f = 0; f < 2; f++)
1104 if (cmp.file[f].desc != NONEXISTENT)
1106 if (f && file_name_cmp (cmp.file[f].name, cmp.file[0].name) == 0)
1108 cmp.file[f].desc = cmp.file[0].desc;
1109 cmp.file[f].stat = cmp.file[0].stat;
1111 else if (STREQ (cmp.file[f].name, "-"))
1113 cmp.file[f].desc = STDIN_FILENO;
1114 if (binary && ! isatty (STDIN_FILENO))
1115 set_binary_mode (STDIN_FILENO, O_BINARY);
1116 if (fstat (STDIN_FILENO, &cmp.file[f].stat) != 0)
1117 cmp.file[f].desc = ERRNO_ENCODE (errno);
1120 if (S_ISREG (cmp.file[f].stat.st_mode))
1122 off_t pos = lseek (STDIN_FILENO, 0, SEEK_CUR);
1124 cmp.file[f].desc = ERRNO_ENCODE (errno);
1126 cmp.file[f].stat.st_size =
1127 MAX (0, cmp.file[f].stat.st_size - pos);
1130 /* POSIX 1003.1-2001 requires current time for
1132 set_mtime_to_now (&cmp.file[f].stat);
1135 else if ((no_dereference_symlinks
1136 ? lstat (cmp.file[f].name, &cmp.file[f].stat)
1137 : stat (cmp.file[f].name, &cmp.file[f].stat))
1139 cmp.file[f].desc = ERRNO_ENCODE (errno);
1143 /* Mark files as nonexistent as needed for -N and -P, if they are
1144 inaccessible empty regular files (the kind of files that 'patch'
1145 creates to indicate nonexistent backups), or if they are
1146 top-level files that do not exist but their counterparts do
1148 for (f = 0; f < 2; f++)
1149 if ((new_file || (f == 0 && unidirectional_new_file))
1150 && (cmp.file[f].desc == UNOPENED
1151 ? (S_ISREG (cmp.file[f].stat.st_mode)
1152 && ! (cmp.file[f].stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO))
1153 && cmp.file[f].stat.st_size == 0)
1154 : ((cmp.file[f].desc == ERRNO_ENCODE (ENOENT)
1155 || cmp.file[f].desc == ERRNO_ENCODE (EBADF))
1157 && (cmp.file[1 - f].desc == UNOPENED
1158 || cmp.file[1 - f].desc == STDIN_FILENO))))
1159 cmp.file[f].desc = NONEXISTENT;
1161 for (f = 0; f < 2; f++)
1162 if (cmp.file[f].desc == NONEXISTENT)
1164 memset (&cmp.file[f].stat, 0, sizeof cmp.file[f].stat);
1165 cmp.file[f].stat.st_mode = cmp.file[1 - f].stat.st_mode;
1168 for (f = 0; f < 2; f++)
1170 int e = ERRNO_DECODE (cmp.file[f].desc);
1174 perror_with_name (cmp.file[f].name);
1175 status = EXIT_TROUBLE;
1179 if (status == EXIT_SUCCESS && ! parent && DIR_P (0) != DIR_P (1))
1181 /* If one is a directory, and it was specified in the command line,
1182 use the file in that dir with the other file's basename. */
1184 int fnm_arg = DIR_P (0);
1185 int dir_arg = 1 - fnm_arg;
1186 char const *fnm = cmp.file[fnm_arg].name;
1187 char const *dir = cmp.file[dir_arg].name;
1188 char const *filename = cmp.file[dir_arg].name = free0
1189 = find_dir_file_pathname (dir, last_component (fnm));
1191 if (STREQ (fnm, "-"))
1192 fatal ("cannot compare '-' to a directory");
1194 if ((no_dereference_symlinks
1195 ? lstat (filename, &cmp.file[dir_arg].stat)
1196 : stat (filename, &cmp.file[dir_arg].stat))
1199 perror_with_name (filename);
1200 status = EXIT_TROUBLE;
1204 if (status != EXIT_SUCCESS)
1206 /* One of the files should exist but does not. */
1208 else if (cmp.file[0].desc == NONEXISTENT
1209 && cmp.file[1].desc == NONEXISTENT)
1211 /* Neither file "exists", so there's nothing to compare. */
1213 else if ((same_files
1214 = (cmp.file[0].desc != NONEXISTENT
1215 && cmp.file[1].desc != NONEXISTENT
1216 && 0 < same_file (&cmp.file[0].stat, &cmp.file[1].stat)
1217 && same_file_attributes (&cmp.file[0].stat,
1218 &cmp.file[1].stat)))
1219 && no_diff_means_no_output)
1221 /* The two named files are actually the same physical file.
1222 We know they are identical without actually reading them. */
1224 else if (DIR_P (0) & DIR_P (1))
1226 if (output_style == OUTPUT_IFDEF)
1227 fatal ("-D option not supported with directories");
1229 /* If both are directories, compare the files in them. */
1231 if (parent && !recursive)
1233 /* But don't compare dir contents one level down
1234 unless -r was specified.
1235 See POSIX 1003.1-2001 for this format. */
1236 message ("Common subdirectories: %s and %s\n",
1237 cmp.file[0].name, cmp.file[1].name);
1240 status = diff_dirs (&cmp, compare_files);
1242 else if ((DIR_P (0) | DIR_P (1))
1244 && !((S_ISREG (cmp.file[0].stat.st_mode)
1245 || S_ISLNK (cmp.file[0].stat.st_mode))
1246 && (S_ISREG (cmp.file[1].stat.st_mode)
1247 || S_ISLNK (cmp.file[1].stat.st_mode)))))
1249 if (cmp.file[0].desc == NONEXISTENT || cmp.file[1].desc == NONEXISTENT)
1251 /* We have a subdirectory that exists only in one directory. */
1253 if ((DIR_P (0) | DIR_P (1))
1256 || (unidirectional_new_file
1257 && cmp.file[0].desc == NONEXISTENT)))
1258 status = diff_dirs (&cmp, compare_files);
1263 /* PARENT must be non-NULL here. */
1265 dir = parent->file[cmp.file[0].desc == NONEXISTENT].name;
1267 /* See POSIX 1003.1-2001 for this format. */
1268 message ("Only in %s: %s\n", dir, name0);
1270 status = EXIT_FAILURE;
1275 /* We have two files that are not to be compared. */
1277 /* See POSIX 1003.1-2001 for this format. */
1278 message5 ("File %s is a %s while file %s is a %s\n",
1279 file_label[0] ? file_label[0] : cmp.file[0].name,
1280 file_type (&cmp.file[0].stat),
1281 file_label[1] ? file_label[1] : cmp.file[1].name,
1282 file_type (&cmp.file[1].stat));
1284 /* This is a difference. */
1285 status = EXIT_FAILURE;
1288 else if (S_ISLNK (cmp.file[0].stat.st_mode)
1289 || S_ISLNK (cmp.file[1].stat.st_mode))
1291 /* We get here only if we use lstat(), not stat(). */
1292 assert (no_dereference_symlinks);
1294 if (S_ISLNK (cmp.file[0].stat.st_mode)
1295 && S_ISLNK (cmp.file[1].stat.st_mode))
1297 /* Compare the values of the symbolic links. */
1298 char *link_value[2] = { NULL, NULL };
1300 for (f = 0; f < 2; f++)
1302 link_value[f] = xreadlink (cmp.file[f].name);
1303 if (link_value[f] == NULL)
1305 perror_with_name (cmp.file[f].name);
1306 status = EXIT_TROUBLE;
1310 if (status == EXIT_SUCCESS)
1312 if ( ! STREQ (link_value[0], link_value[1]))
1314 message ("Symbolic links %s and %s differ\n",
1315 cmp.file[0].name, cmp.file[1].name);
1316 /* This is a difference. */
1317 status = EXIT_FAILURE;
1320 for (f = 0; f < 2; f++)
1321 free (link_value[f]);
1325 /* We have two files that are not to be compared, because
1326 one of them is a symbolic link and the other one is not. */
1328 message5 ("File %s is a %s while file %s is a %s\n",
1329 file_label[0] ? file_label[0] : cmp.file[0].name,
1330 file_type (&cmp.file[0].stat),
1331 file_label[1] ? file_label[1] : cmp.file[1].name,
1332 file_type (&cmp.file[1].stat));
1334 /* This is a difference. */
1335 status = EXIT_FAILURE;
1338 else if (files_can_be_treated_as_binary
1339 && S_ISREG (cmp.file[0].stat.st_mode)
1340 && S_ISREG (cmp.file[1].stat.st_mode)
1341 && cmp.file[0].stat.st_size != cmp.file[1].stat.st_size)
1343 message ("Files %s and %s differ\n",
1344 file_label[0] ? file_label[0] : cmp.file[0].name,
1345 file_label[1] ? file_label[1] : cmp.file[1].name);
1346 status = EXIT_FAILURE;
1350 /* Both exist and neither is a directory. */
1352 /* Open the files and record their descriptors. */
1354 int oflags = O_RDONLY | (binary ? O_BINARY : 0);
1356 if (cmp.file[0].desc == UNOPENED)
1357 if ((cmp.file[0].desc = open (cmp.file[0].name, oflags, 0)) < 0)
1359 perror_with_name (cmp.file[0].name);
1360 status = EXIT_TROUBLE;
1362 if (cmp.file[1].desc == UNOPENED)
1365 cmp.file[1].desc = cmp.file[0].desc;
1366 else if ((cmp.file[1].desc = open (cmp.file[1].name, oflags, 0)) < 0)
1368 perror_with_name (cmp.file[1].name);
1369 status = EXIT_TROUBLE;
1373 /* Compare the files, if no error was found. */
1375 if (status == EXIT_SUCCESS)
1376 status = diff_2_files (&cmp);
1378 /* Close the file descriptors. */
1380 if (0 <= cmp.file[0].desc && close (cmp.file[0].desc) != 0)
1382 perror_with_name (cmp.file[0].name);
1383 status = EXIT_TROUBLE;
1385 if (0 <= cmp.file[1].desc && cmp.file[0].desc != cmp.file[1].desc
1386 && close (cmp.file[1].desc) != 0)
1388 perror_with_name (cmp.file[1].name);
1389 status = EXIT_TROUBLE;
1393 /* Now the comparison has been done, if no error prevented it,
1394 and STATUS is the value this function will return. */
1396 if (status == EXIT_SUCCESS)
1398 if (report_identical_files && !DIR_P (0))
1399 message ("Files %s and %s are identical\n",
1400 file_label[0] ? file_label[0] : cmp.file[0].name,
1401 file_label[1] ? file_label[1] : cmp.file[1].name);
1405 /* Flush stdout so that the user sees differences immediately.
1406 This can hurt performance, unfortunately. */
1407 if (fflush (stdout) != 0)
1408 pfatal_with_name (_("standard output"));