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 textdomain (PACKAGE
);
294 function_regexp_list
.buf
= &function_regexp
;
295 ignore_regexp_list
.buf
= &ignore_regexp
;
296 re_set_syntax (RE_SYNTAX_GREP
| RE_NO_POSIX_BACKTRACKING
);
297 excluded
= new_exclude ();
298 presume_output_tty
= false;
300 /* Decode the options. */
302 while ((c
= getopt_long (argc
, argv
, shortopts
, longopts
, NULL
)) != -1)
319 ocontext
= (! ISDIGIT (prev
)
321 : (ocontext
- (c
- '0' <= CONTEXT_MAX
% 10)
323 ? 10 * ocontext
+ (c
- '0')
332 if (ignore_white_space
< IGNORE_SPACE_CHANGE
)
333 ignore_white_space
= IGNORE_SPACE_CHANGE
;
337 if (ignore_white_space
< IGNORE_SPACE_CHANGE
)
338 ignore_white_space
|= IGNORE_TRAILING_SPACE
;
342 ignore_blank_lines
= true;
350 numval
= strtoumax (optarg
, &numend
, 10);
352 try_help ("invalid context length '%s'", optarg
);
353 if (CONTEXT_MAX
< numval
)
354 numval
= CONTEXT_MAX
;
359 specify_style (c
== 'U' ? OUTPUT_UNIFIED
: OUTPUT_CONTEXT
);
360 if (context
< numval
)
362 explicit_context
= true;
367 specify_style (OUTPUT_CONTEXT
);
377 specify_style (OUTPUT_IFDEF
);
379 static char const C_ifdef_group_formats
[] =
380 "%%=%c#ifndef %s\n%%<#endif /* ! %s */\n%c#ifdef %s\n%%>#endif /* %s */\n%c#ifndef %s\n%%<#else /* %s */\n%%>#endif /* %s */\n";
381 char *b
= xmalloc (sizeof C_ifdef_group_formats
382 + 7 * strlen (optarg
) - 14 /* 7*"%s" */
383 - 8 /* 5*"%%" + 3*"%c" */);
384 sprintf (b
, C_ifdef_group_formats
,
388 optarg
, optarg
, optarg
);
389 for (i
= 0; i
< sizeof group_format
/ sizeof group_format
[0]; i
++)
391 specify_value (&group_format
[i
], b
, "-D");
398 specify_style (OUTPUT_ED
);
402 if (ignore_white_space
< IGNORE_SPACE_CHANGE
)
403 ignore_white_space
|= IGNORE_TAB_EXPANSION
;
407 specify_style (OUTPUT_FORWARD_ED
);
411 add_regexp (&function_regexp_list
, optarg
);
415 /* Split the files into chunks for faster processing.
416 Usually does not change the result.
418 This currently has no effect. */
422 speed_large_files
= true;
430 add_regexp (&ignore_regexp_list
, optarg
);
435 try_help ("pagination not supported on this host", NULL
);
438 /* Pagination requires forking and waiting, and
439 System V fork+wait does not work if SIGCHLD is ignored. */
440 signal (SIGCHLD
, SIG_DFL
);
446 file_label
[0] = optarg
;
447 else if (!file_label
[1])
448 file_label
[1] = optarg
;
450 fatal ("too many file label options");
454 specify_style (OUTPUT_RCS
);
462 show_c_function
= true;
463 add_regexp (&function_regexp_list
, "^[[:alpha:]$_]");
467 unidirectional_new_file
= true;
479 report_identical_files
= true;
483 specify_value (&starting_file
, optarg
, "-S");
495 specify_style (OUTPUT_UNIFIED
);
501 version_etc (stdout
, PROGRAM_NAME
, PACKAGE_NAME
, Version
,
502 AUTHORS
, (char *) NULL
);
507 ignore_white_space
= IGNORE_ALL_SPACE
;
511 add_exclude (excluded
, optarg
, exclude_options ());
515 if (add_exclude_file (add_exclude
, excluded
, optarg
,
516 exclude_options (), '\n'))
517 pfatal_with_name (optarg
);
521 specify_style (OUTPUT_SDIFF
);
525 numval
= strtoumax (optarg
, &numend
, 10);
526 if (! (0 < numval
&& numval
<= SIZE_MAX
) || *numend
)
527 try_help ("invalid width '%s'", optarg
);
531 fatal ("conflicting width options");
539 if (! isatty (STDOUT_FILENO
))
540 set_binary_mode (STDOUT_FILENO
, O_BINARY
);
544 case FROM_FILE_OPTION
:
545 specify_value (&from_file
, optarg
, "--from-file");
553 case HORIZON_LINES_OPTION
:
554 numval
= strtoumax (optarg
, &numend
, 10);
556 try_help ("invalid horizon length '%s'", optarg
);
557 horizon_lines
= MAX (horizon_lines
, MIN (numval
, LIN_MAX
));
560 case IGNORE_FILE_NAME_CASE_OPTION
:
561 ignore_file_name_case
= true;
564 case INHIBIT_HUNK_MERGE_OPTION
:
565 /* This option is obsolete, but accept it for backward
569 case LEFT_COLUMN_OPTION
:
573 case LINE_FORMAT_OPTION
:
574 specify_style (OUTPUT_IFDEF
);
575 for (i
= 0; i
< sizeof line_format
/ sizeof line_format
[0]; i
++)
576 specify_value (&line_format
[i
], optarg
, "--line-format");
579 case NO_DEREFERENCE_OPTION
:
580 no_dereference_symlinks
= true;
583 case NO_IGNORE_FILE_NAME_CASE_OPTION
:
584 ignore_file_name_case
= false;
588 specify_style (OUTPUT_NORMAL
);
591 case SDIFF_MERGE_ASSIST_OPTION
:
592 specify_style (OUTPUT_SDIFF
);
593 sdiff_merge_assist
= true;
596 case STRIP_TRAILING_CR_OPTION
:
597 strip_trailing_cr
= true;
600 case SUPPRESS_BLANK_EMPTY_OPTION
:
601 suppress_blank_empty
= true;
604 case SUPPRESS_COMMON_LINES_OPTION
:
605 suppress_common_lines
= true;
609 numval
= strtoumax (optarg
, &numend
, 10);
610 if (! (0 < numval
&& numval
<= SIZE_MAX
- GUTTER_WIDTH_MINIMUM
)
612 try_help ("invalid tabsize '%s'", optarg
);
613 if (tabsize
!= numval
)
616 fatal ("conflicting tabsize options");
622 specify_value (&to_file
, optarg
, "--to-file");
625 case UNCHANGED_LINE_FORMAT_OPTION
:
626 case OLD_LINE_FORMAT_OPTION
:
627 case NEW_LINE_FORMAT_OPTION
:
628 specify_style (OUTPUT_IFDEF
);
629 c
-= UNCHANGED_LINE_FORMAT_OPTION
;
630 specify_value (&line_format
[c
], optarg
, line_format_option
[c
]);
633 case UNCHANGED_GROUP_FORMAT_OPTION
:
634 case OLD_GROUP_FORMAT_OPTION
:
635 case NEW_GROUP_FORMAT_OPTION
:
636 case CHANGED_GROUP_FORMAT_OPTION
:
637 specify_style (OUTPUT_IFDEF
);
638 c
-= UNCHANGED_GROUP_FORMAT_OPTION
;
639 specify_value (&group_format
[c
], optarg
, group_format_option
[c
]);
643 specify_colors_style (optarg
);
646 case COLOR_PALETTE_OPTION
:
647 set_color_palette (optarg
);
650 case PRESUME_OUTPUT_TTY_OPTION
:
651 presume_output_tty
= true;
655 try_help (NULL
, NULL
);
660 if (colors_style
== AUTO
)
662 char const *t
= getenv ("TERM");
663 if (t
&& STREQ (t
, "dumb"))
664 colors_style
= NEVER
;
667 if (output_style
== OUTPUT_UNSPECIFIED
)
671 specify_style (OUTPUT_CONTEXT
);
676 specify_style (OUTPUT_NORMAL
);
679 if (output_style
!= OUTPUT_CONTEXT
|| hard_locale (LC_TIME
))
681 #if (defined STAT_TIMESPEC || defined STAT_TIMESPEC_NS \
682 || defined HAVE_STRUCT_STAT_ST_SPARE1)
683 time_format
= "%Y-%m-%d %H:%M:%S.%N %z";
685 time_format
= "%Y-%m-%d %H:%M:%S %z";
690 /* See POSIX 1003.1-2001 for this format. */
691 time_format
= "%a %b %e %T %Y";
695 && (output_style
== OUTPUT_CONTEXT
696 || output_style
== OUTPUT_UNIFIED
)
697 && (context
< ocontext
698 || (ocontext
< context
&& ! explicit_context
)))
707 /* Maximize first the half line width, and then the gutter width,
708 according to the following constraints:
710 1. Two half lines plus a gutter must fit in a line.
711 2. If the half line width is nonzero:
712 a. The gutter width is at least GUTTER_WIDTH_MINIMUM.
713 b. If tabs are not expanded to spaces,
714 a half line plus a gutter is an integral number of tabs,
715 so that tabs in the right column line up. */
717 size_t t
= expand_tabs
? 1 : tabsize
;
719 size_t t_plus_g
= t
+ GUTTER_WIDTH_MINIMUM
;
720 size_t unaligned_off
= (w
>> 1) + (t_plus_g
>> 1) + (w
& t_plus_g
& 1);
721 size_t off
= unaligned_off
- unaligned_off
% t
;
722 sdiff_half_width
= (off
<= GUTTER_WIDTH_MINIMUM
|| w
<= off
724 : MIN (off
- GUTTER_WIDTH_MINIMUM
, w
- off
));
725 sdiff_column2_offset
= sdiff_half_width
? off
: w
;
728 /* Make the horizon at least as large as the context, so that
729 shift_boundaries has more freedom to shift the first and last hunks. */
730 if (horizon_lines
< context
)
731 horizon_lines
= context
;
733 summarize_regexp_list (&function_regexp_list
);
734 summarize_regexp_list (&ignore_regexp_list
);
736 if (output_style
== OUTPUT_IFDEF
)
738 for (i
= 0; i
< sizeof line_format
/ sizeof line_format
[0]; i
++)
740 line_format
[i
] = "%l\n";
741 if (!group_format
[OLD
])
743 = group_format
[CHANGED
] ? group_format
[CHANGED
] : "%<";
744 if (!group_format
[NEW
])
746 = group_format
[CHANGED
] ? group_format
[CHANGED
] : "%>";
747 if (!group_format
[UNCHANGED
])
748 group_format
[UNCHANGED
] = "%=";
749 if (!group_format
[CHANGED
])
750 group_format
[CHANGED
] = concat (group_format
[OLD
],
751 group_format
[NEW
], "");
754 no_diff_means_no_output
=
755 (output_style
== OUTPUT_IFDEF
?
756 (!*group_format
[UNCHANGED
]
757 || (STREQ (group_format
[UNCHANGED
], "%=")
758 && !*line_format
[UNCHANGED
]))
759 : (output_style
!= OUTPUT_SDIFF
) | suppress_common_lines
);
761 files_can_be_treated_as_binary
=
763 & ~ (ignore_blank_lines
| ignore_case
| strip_trailing_cr
764 | (ignore_regexp_list
.regexps
|| ignore_white_space
)));
766 switch_string
= option_list (argv
+ 1, optind
- 1);
771 fatal ("--from-file and --to-file both specified");
773 for (; optind
< argc
; optind
++)
775 int status
= compare_files (NULL
, from_file
, argv
[optind
]);
776 if (exit_status
< status
)
777 exit_status
= status
;
783 for (; optind
< argc
; optind
++)
785 int status
= compare_files (NULL
, argv
[optind
], to_file
);
786 if (exit_status
< status
)
787 exit_status
= status
;
791 if (argc
- optind
!= 2)
793 if (argc
- optind
< 2)
794 try_help ("missing operand after '%s'", argv
[argc
- 1]);
796 try_help ("extra operand '%s'", argv
[optind
+ 2]);
799 exit_status
= compare_files (NULL
, argv
[optind
], argv
[optind
+ 1]);
803 /* Print any messages that were saved up for last. */
804 print_message_queue ();
811 /* Append to REGLIST the regexp PATTERN. */
814 add_regexp (struct regexp_list
*reglist
, char const *pattern
)
816 size_t patlen
= strlen (pattern
);
817 char const *m
= re_compile_pattern (pattern
, patlen
, reglist
->buf
);
820 error (EXIT_TROUBLE
, 0, "%s: %s", pattern
, m
);
823 char *regexps
= reglist
->regexps
;
824 size_t len
= reglist
->len
;
825 bool multiple_regexps
= reglist
->multiple_regexps
= regexps
!= 0;
826 size_t newlen
= reglist
->len
= len
+ 2 * multiple_regexps
+ patlen
;
827 size_t size
= reglist
->size
;
835 while (size
<= newlen
);
837 reglist
->size
= size
;
838 reglist
->regexps
= regexps
= xrealloc (regexps
, size
);
840 if (multiple_regexps
)
842 regexps
[len
++] = '\\';
843 regexps
[len
++] = '|';
845 memcpy (regexps
+ len
, pattern
, patlen
+ 1);
849 /* Ensure that REGLIST represents the disjunction of its regexps.
850 This is done here, rather than earlier, to avoid O(N^2) behavior. */
853 summarize_regexp_list (struct regexp_list
*reglist
)
855 if (reglist
->regexps
)
857 /* At least one regexp was specified. Allocate a fastmap for it. */
858 reglist
->buf
->fastmap
= xmalloc (1 << CHAR_BIT
);
859 if (reglist
->multiple_regexps
)
861 /* Compile the disjunction of the regexps.
862 (If just one regexp was specified, it is already compiled.) */
863 char const *m
= re_compile_pattern (reglist
->regexps
, reglist
->len
,
866 die (EXIT_TROUBLE
, 0, "%s: %s", reglist
->regexps
, m
);
872 try_help (char const *reason_msgid
, char const *operand
)
875 error (0, 0, _(reason_msgid
), operand
);
876 die (EXIT_TROUBLE
, 0, _("Try '%s --help' for more information."),
884 fatal ("write failed");
885 else if (fclose (stdout
) != 0)
886 pfatal_with_name (_("standard output"));
889 static char const * const option_help_msgid
[] = {
890 N_(" --normal output a normal diff (the default)"),
891 N_("-q, --brief report only when files differ"),
892 N_("-s, --report-identical-files report when two files are the same"),
893 N_("-c, -C NUM, --context[=NUM] output NUM (default 3) lines of copied context"),
894 N_("-u, -U NUM, --unified[=NUM] output NUM (default 3) lines of unified context"),
895 N_("-e, --ed output an ed script"),
896 N_("-n, --rcs output an RCS format diff"),
897 N_("-y, --side-by-side output in two columns"),
898 N_("-W, --width=NUM output at most NUM (default 130) print columns"),
899 N_(" --left-column output only the left column of common lines"),
900 N_(" --suppress-common-lines do not output common lines"),
902 N_("-p, --show-c-function show which C function each change is in"),
903 N_("-F, --show-function-line=RE show the most recent line matching RE"),
904 N_(" --label LABEL use LABEL instead of file name and timestamp\n"
905 " (can be repeated)"),
907 N_("-t, --expand-tabs expand tabs to spaces in output"),
908 N_("-T, --initial-tab make tabs line up by prepending a tab"),
909 N_(" --tabsize=NUM tab stops every NUM (default 8) print columns"),
910 N_(" --suppress-blank-empty suppress space or tab before empty output lines"),
911 N_("-l, --paginate pass output through 'pr' to paginate it"),
913 N_("-r, --recursive recursively compare any subdirectories found"),
914 N_(" --no-dereference don't follow symbolic links"),
915 N_("-N, --new-file treat absent files as empty"),
916 N_(" --unidirectional-new-file treat absent first files as empty"),
917 N_(" --ignore-file-name-case ignore case when comparing file names"),
918 N_(" --no-ignore-file-name-case consider case when comparing file names"),
919 N_("-x, --exclude=PAT exclude files that match PAT"),
920 N_("-X, --exclude-from=FILE exclude files that match any pattern in FILE"),
921 N_("-S, --starting-file=FILE start with FILE when comparing directories"),
922 N_(" --from-file=FILE1 compare FILE1 to all operands;\n"
923 " FILE1 can be a directory"),
924 N_(" --to-file=FILE2 compare all operands to FILE2;\n"
925 " FILE2 can be a directory"),
927 N_("-i, --ignore-case ignore case differences in file contents"),
928 N_("-E, --ignore-tab-expansion ignore changes due to tab expansion"),
929 N_("-Z, --ignore-trailing-space ignore white space at line end"),
930 N_("-b, --ignore-space-change ignore changes in the amount of white space"),
931 N_("-w, --ignore-all-space ignore all white space"),
932 N_("-B, --ignore-blank-lines ignore changes where lines are all blank"),
933 N_("-I, --ignore-matching-lines=RE ignore changes where all lines match RE"),
935 N_("-a, --text treat all files as text"),
936 N_(" --strip-trailing-cr strip trailing carriage return on input"),
938 N_(" --binary read and write data in binary mode"),
941 N_("-D, --ifdef=NAME output merged file with '#ifdef NAME' diffs"),
942 N_(" --GTYPE-group-format=GFMT format GTYPE input groups with GFMT"),
943 N_(" --line-format=LFMT format all input lines with LFMT"),
944 N_(" --LTYPE-line-format=LFMT format LTYPE input lines with LFMT"),
945 N_(" These format options provide fine-grained control over the output\n"
946 " of diff, generalizing -D/--ifdef."),
947 N_(" LTYPE is 'old', 'new', or 'unchanged'. GTYPE is LTYPE or 'changed'."),
948 N_(" GFMT (only) may contain:\n\
949 %< lines from FILE1\n\
950 %> lines from FILE2\n\
951 %= lines common to FILE1 and FILE2\n\
952 %[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER\n\
953 LETTERs are as follows for new group, lower case for old group:\n\
954 F first line number\n\
955 L last line number\n\
956 N number of lines = L-F+1\n\
959 %(A=B?T:E) if A equals B then T else E"),
960 N_(" LFMT (only) may contain:\n\
961 %L contents of line\n\
962 %l contents of line, excluding any trailing newline\n\
963 %[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number"),
964 N_(" Both GFMT and LFMT may contain:\n\
966 %c'C' the single character C\n\
967 %c'\\OOO' the character with octal code OOO\n\
968 C the character C (other characters represent themselves)"),
970 N_("-d, --minimal try hard to find a smaller set of changes"),
971 N_(" --horizon-lines=NUM keep NUM lines of the common prefix and suffix"),
972 N_(" --speed-large-files assume large files and many scattered small changes"),
973 N_(" --color[=WHEN] colorize the output; WHEN can be 'never', 'always',\n"
974 " or 'auto' (the default)"),
975 N_(" --palette=PALETTE the colors to use when --color is active; PALETTE is\n"
976 " a colon-separated list of terminfo capabilities"),
978 N_(" --help display this help and exit"),
979 N_("-v, --version output version information and exit"),
981 N_("FILES are 'FILE1 FILE2' or 'DIR1 DIR2' or 'DIR FILE' or 'FILE DIR'."),
982 N_("If --from-file or --to-file is given, there are no restrictions on FILE(s)."),
983 N_("If a FILE is '-', read standard input."),
984 N_("Exit status is 0 if inputs are the same, 1 if different, 2 if trouble."),
991 char const * const *p
;
993 printf (_("Usage: %s [OPTION]... FILES\n"), program_name
);
994 printf ("%s\n\n", _("Compare FILES line by line."));
997 Mandatory arguments to long options are mandatory for short options too.\n\
1000 for (p
= option_help_msgid
; *p
; p
++)
1006 char const *msg
= _(*p
);
1008 while ((nl
= strchr (msg
, '\n')))
1010 int msglen
= nl
+ 1 - msg
;
1011 /* This assertion is solely to avoid a warning from
1012 gcc's -Wformat-overflow=. */
1013 assert (msglen
< 4096);
1014 printf (" %.*s", msglen
, msg
);
1018 printf (" %s\n" + 2 * (*msg
!= ' ' && *msg
!= '-'), msg
);
1021 emit_bug_reporting_address ();
1024 /* Set VAR to VALUE, reporting an OPTION error if this is a
1027 specify_value (char const **var
, char const *value
, char const *option
)
1029 if (*var
&& ! STREQ (*var
, value
))
1031 error (0, 0, _("conflicting %s option value '%s'"), option
, value
);
1032 try_help (NULL
, NULL
);
1037 /* Set the output style to STYLE, diagnosing conflicts. */
1039 specify_style (enum output_style style
)
1041 if (output_style
!= style
)
1043 if (output_style
!= OUTPUT_UNSPECIFIED
)
1044 try_help ("conflicting output style options", NULL
);
1045 output_style
= style
;
1049 /* Set the color mode. */
1051 specify_colors_style (char const *value
)
1053 if (value
== NULL
|| STREQ (value
, "auto"))
1054 colors_style
= AUTO
;
1055 else if (STREQ (value
, "always"))
1056 colors_style
= ALWAYS
;
1057 else if (STREQ (value
, "never"))
1058 colors_style
= NEVER
;
1060 try_help ("invalid color '%s'", value
);
1064 /* Set the last-modified time of *ST to be the current time. */
1067 set_mtime_to_now (struct stat
*st
)
1069 #ifdef STAT_TIMESPEC
1070 gettime (&STAT_TIMESPEC (st
, st_mtim
));
1074 st
->st_mtime
= t
.tv_sec
;
1075 # if defined STAT_TIMESPEC_NS
1076 STAT_TIMESPEC_NS (st
, st_mtim
) = t
.tv_nsec
;
1077 # elif defined HAVE_STRUCT_STAT_ST_SPARE1
1078 st
->st_spare1
= t
.tv_nsec
/ 1000;
1083 /* Compare two files (or dirs) with parent comparison PARENT
1084 and names NAME0 and NAME1.
1085 (If PARENT is null, then the first name is just NAME0, etc.)
1086 This is self-contained; it opens the files and closes them.
1088 Value is EXIT_SUCCESS if files are the same, EXIT_FAILURE if
1089 different, EXIT_TROUBLE if there is a problem opening them. */
1092 compare_files (struct comparison
const *parent
,
1096 struct comparison cmp
;
1097 #define DIR_P(f) (S_ISDIR (cmp.file[f].stat.st_mode) != 0)
1099 int status
= EXIT_SUCCESS
;
1104 /* If this is directory comparison, perhaps we have a file
1105 that exists only in one of the directories.
1106 If so, just print a message to that effect. */
1108 if (! ((name0
&& name1
)
1109 || (unidirectional_new_file
&& name1
)
1112 char const *name
= name0
? name0
: name1
;
1113 char const *dir
= parent
->file
[!name0
].name
;
1115 /* See POSIX 1003.1-2001 for this format. */
1116 message ("Only in %s: %s\n", dir
, name
);
1118 /* Return EXIT_FAILURE so that diff_dirs will return
1119 EXIT_FAILURE ("some files differ"). */
1120 return EXIT_FAILURE
;
1123 memset (cmp
.file
, 0, sizeof cmp
.file
);
1124 cmp
.parent
= parent
;
1126 /* cmp.file[f].desc markers */
1127 #define NONEXISTENT (-1) /* nonexistent file */
1128 #define UNOPENED (-2) /* unopened file (e.g. directory) */
1129 #define ERRNO_ENCODE(errno) (-3 - (errno)) /* encoded errno value */
1131 #define ERRNO_DECODE(desc) (-3 - (desc)) /* inverse of ERRNO_ENCODE */
1133 cmp
.file
[0].desc
= name0
? UNOPENED
: NONEXISTENT
;
1134 cmp
.file
[1].desc
= name1
? UNOPENED
: NONEXISTENT
;
1136 /* Now record the full name of each file, including nonexistent ones. */
1147 cmp
.file
[0].name
= name0
;
1148 cmp
.file
[1].name
= name1
;
1152 cmp
.file
[0].name
= free0
1153 = file_name_concat (parent
->file
[0].name
, name0
, NULL
);
1154 cmp
.file
[1].name
= free1
1155 = file_name_concat (parent
->file
[1].name
, name1
, NULL
);
1158 /* Stat the files. */
1160 for (f
= 0; f
< 2; f
++)
1162 if (cmp
.file
[f
].desc
!= NONEXISTENT
)
1164 if (f
&& file_name_cmp (cmp
.file
[f
].name
, cmp
.file
[0].name
) == 0)
1166 cmp
.file
[f
].desc
= cmp
.file
[0].desc
;
1167 cmp
.file
[f
].stat
= cmp
.file
[0].stat
;
1169 else if (STREQ (cmp
.file
[f
].name
, "-"))
1171 cmp
.file
[f
].desc
= STDIN_FILENO
;
1172 if (binary
&& ! isatty (STDIN_FILENO
))
1173 set_binary_mode (STDIN_FILENO
, O_BINARY
);
1174 if (fstat (STDIN_FILENO
, &cmp
.file
[f
].stat
) != 0)
1175 cmp
.file
[f
].desc
= ERRNO_ENCODE (errno
);
1178 if (S_ISREG (cmp
.file
[f
].stat
.st_mode
))
1180 off_t pos
= lseek (STDIN_FILENO
, 0, SEEK_CUR
);
1182 cmp
.file
[f
].desc
= ERRNO_ENCODE (errno
);
1184 cmp
.file
[f
].stat
.st_size
=
1185 MAX (0, cmp
.file
[f
].stat
.st_size
- pos
);
1188 /* POSIX 1003.1-2001 requires current time for
1190 set_mtime_to_now (&cmp
.file
[f
].stat
);
1193 else if ((no_dereference_symlinks
1194 ? lstat (cmp
.file
[f
].name
, &cmp
.file
[f
].stat
)
1195 : stat (cmp
.file
[f
].name
, &cmp
.file
[f
].stat
))
1197 cmp
.file
[f
].desc
= ERRNO_ENCODE (errno
);
1201 /* Mark files as nonexistent as needed for -N and -P, if they are
1202 inaccessible empty regular files (the kind of files that 'patch'
1203 creates to indicate nonexistent backups), or if they are
1204 top-level files that do not exist but their counterparts do
1206 for (f
= 0; f
< 2; f
++)
1207 if ((new_file
|| (f
== 0 && unidirectional_new_file
))
1208 && (cmp
.file
[f
].desc
== UNOPENED
1209 ? (S_ISREG (cmp
.file
[f
].stat
.st_mode
)
1210 && ! (cmp
.file
[f
].stat
.st_mode
& (S_IRWXU
| S_IRWXG
| S_IRWXO
))
1211 && cmp
.file
[f
].stat
.st_size
== 0)
1212 : ((cmp
.file
[f
].desc
== ERRNO_ENCODE (ENOENT
)
1213 || cmp
.file
[f
].desc
== ERRNO_ENCODE (EBADF
))
1215 && (cmp
.file
[1 - f
].desc
== UNOPENED
1216 || cmp
.file
[1 - f
].desc
== STDIN_FILENO
))))
1217 cmp
.file
[f
].desc
= NONEXISTENT
;
1219 for (f
= 0; f
< 2; f
++)
1220 if (cmp
.file
[f
].desc
== NONEXISTENT
)
1222 memset (&cmp
.file
[f
].stat
, 0, sizeof cmp
.file
[f
].stat
);
1223 cmp
.file
[f
].stat
.st_mode
= cmp
.file
[1 - f
].stat
.st_mode
;
1226 for (f
= 0; f
< 2; f
++)
1228 int e
= ERRNO_DECODE (cmp
.file
[f
].desc
);
1232 perror_with_name (cmp
.file
[f
].name
);
1233 status
= EXIT_TROUBLE
;
1237 if (status
== EXIT_SUCCESS
&& ! parent
&& DIR_P (0) != DIR_P (1))
1239 /* If one is a directory, and it was specified in the command line,
1240 use the file in that dir with the other file's basename. */
1242 int fnm_arg
= DIR_P (0);
1243 int dir_arg
= 1 - fnm_arg
;
1244 char const *fnm
= cmp
.file
[fnm_arg
].name
;
1245 char const *dir
= cmp
.file
[dir_arg
].name
;
1246 char const *filename
= cmp
.file
[dir_arg
].name
= free0
1247 = find_dir_file_pathname (dir
, last_component (fnm
));
1249 if (STREQ (fnm
, "-"))
1250 fatal ("cannot compare '-' to a directory");
1252 if ((no_dereference_symlinks
1253 ? lstat (filename
, &cmp
.file
[dir_arg
].stat
)
1254 : stat (filename
, &cmp
.file
[dir_arg
].stat
))
1257 perror_with_name (filename
);
1258 status
= EXIT_TROUBLE
;
1262 if (status
!= EXIT_SUCCESS
)
1264 /* One of the files should exist but does not. */
1266 else if (cmp
.file
[0].desc
== NONEXISTENT
1267 && cmp
.file
[1].desc
== NONEXISTENT
)
1269 /* Neither file "exists", so there's nothing to compare. */
1271 else if ((same_files
1272 = (cmp
.file
[0].desc
!= NONEXISTENT
1273 && cmp
.file
[1].desc
!= NONEXISTENT
1274 && 0 < same_file (&cmp
.file
[0].stat
, &cmp
.file
[1].stat
)
1275 && same_file_attributes (&cmp
.file
[0].stat
,
1276 &cmp
.file
[1].stat
)))
1277 && no_diff_means_no_output
)
1279 /* The two named files are actually the same physical file.
1280 We know they are identical without actually reading them. */
1282 else if (DIR_P (0) & DIR_P (1))
1284 if (output_style
== OUTPUT_IFDEF
)
1285 fatal ("-D option not supported with directories");
1287 /* If both are directories, compare the files in them. */
1289 if (parent
&& !recursive
)
1291 /* But don't compare dir contents one level down
1292 unless -r was specified.
1293 See POSIX 1003.1-2001 for this format. */
1294 message ("Common subdirectories: %s and %s\n",
1295 cmp
.file
[0].name
, cmp
.file
[1].name
);
1298 status
= diff_dirs (&cmp
, compare_files
);
1300 else if ((DIR_P (0) | DIR_P (1))
1302 && !((S_ISREG (cmp
.file
[0].stat
.st_mode
)
1303 || S_ISLNK (cmp
.file
[0].stat
.st_mode
))
1304 && (S_ISREG (cmp
.file
[1].stat
.st_mode
)
1305 || S_ISLNK (cmp
.file
[1].stat
.st_mode
)))))
1307 if (cmp
.file
[0].desc
== NONEXISTENT
|| cmp
.file
[1].desc
== NONEXISTENT
)
1309 /* We have a subdirectory that exists only in one directory. */
1311 if ((DIR_P (0) | DIR_P (1))
1314 || (unidirectional_new_file
1315 && cmp
.file
[0].desc
== NONEXISTENT
)))
1316 status
= diff_dirs (&cmp
, compare_files
);
1321 /* PARENT must be non-NULL here. */
1323 dir
= parent
->file
[cmp
.file
[0].desc
== NONEXISTENT
].name
;
1325 /* See POSIX 1003.1-2001 for this format. */
1326 message ("Only in %s: %s\n", dir
, name0
);
1328 status
= EXIT_FAILURE
;
1333 /* We have two files that are not to be compared. */
1335 /* See POSIX 1003.1-2001 for this format. */
1336 message5 ("File %s is a %s while file %s is a %s\n",
1337 file_label
[0] ? file_label
[0] : cmp
.file
[0].name
,
1338 file_type (&cmp
.file
[0].stat
),
1339 file_label
[1] ? file_label
[1] : cmp
.file
[1].name
,
1340 file_type (&cmp
.file
[1].stat
));
1342 /* This is a difference. */
1343 status
= EXIT_FAILURE
;
1346 else if (S_ISLNK (cmp
.file
[0].stat
.st_mode
)
1347 || S_ISLNK (cmp
.file
[1].stat
.st_mode
))
1349 /* We get here only if we use lstat(), not stat(). */
1350 assert (no_dereference_symlinks
);
1352 if (S_ISLNK (cmp
.file
[0].stat
.st_mode
)
1353 && S_ISLNK (cmp
.file
[1].stat
.st_mode
))
1355 /* Compare the values of the symbolic links. */
1356 char *link_value
[2] = { NULL
, NULL
};
1358 for (f
= 0; f
< 2; f
++)
1360 link_value
[f
] = xreadlink (cmp
.file
[f
].name
);
1361 if (link_value
[f
] == NULL
)
1363 perror_with_name (cmp
.file
[f
].name
);
1364 status
= EXIT_TROUBLE
;
1368 if (status
== EXIT_SUCCESS
)
1370 if ( ! STREQ (link_value
[0], link_value
[1]))
1372 message ("Symbolic links %s and %s differ\n",
1373 cmp
.file
[0].name
, cmp
.file
[1].name
);
1374 /* This is a difference. */
1375 status
= EXIT_FAILURE
;
1378 for (f
= 0; f
< 2; f
++)
1379 free (link_value
[f
]);
1383 /* We have two files that are not to be compared, because
1384 one of them is a symbolic link and the other one is not. */
1386 message5 ("File %s is a %s while file %s is a %s\n",
1387 file_label
[0] ? file_label
[0] : cmp
.file
[0].name
,
1388 file_type (&cmp
.file
[0].stat
),
1389 file_label
[1] ? file_label
[1] : cmp
.file
[1].name
,
1390 file_type (&cmp
.file
[1].stat
));
1392 /* This is a difference. */
1393 status
= EXIT_FAILURE
;
1396 else if (files_can_be_treated_as_binary
1397 && S_ISREG (cmp
.file
[0].stat
.st_mode
)
1398 && S_ISREG (cmp
.file
[1].stat
.st_mode
)
1399 && cmp
.file
[0].stat
.st_size
!= cmp
.file
[1].stat
.st_size
1400 && 0 < cmp
.file
[0].stat
.st_size
1401 && 0 < cmp
.file
[1].stat
.st_size
)
1403 message ("Files %s and %s differ\n",
1404 file_label
[0] ? file_label
[0] : cmp
.file
[0].name
,
1405 file_label
[1] ? file_label
[1] : cmp
.file
[1].name
);
1406 status
= EXIT_FAILURE
;
1410 /* Both exist and neither is a directory. */
1412 /* Open the files and record their descriptors. */
1414 int oflags
= O_RDONLY
| (binary
? O_BINARY
: 0);
1416 if (cmp
.file
[0].desc
== UNOPENED
)
1417 if ((cmp
.file
[0].desc
= open (cmp
.file
[0].name
, oflags
, 0)) < 0)
1419 perror_with_name (cmp
.file
[0].name
);
1420 status
= EXIT_TROUBLE
;
1422 if (cmp
.file
[1].desc
== UNOPENED
)
1425 cmp
.file
[1].desc
= cmp
.file
[0].desc
;
1426 else if ((cmp
.file
[1].desc
= open (cmp
.file
[1].name
, oflags
, 0)) < 0)
1428 perror_with_name (cmp
.file
[1].name
);
1429 status
= EXIT_TROUBLE
;
1433 /* Compare the files, if no error was found. */
1435 if (status
== EXIT_SUCCESS
)
1436 status
= diff_2_files (&cmp
);
1438 /* Close the file descriptors. */
1440 if (0 <= cmp
.file
[0].desc
&& close (cmp
.file
[0].desc
) != 0)
1442 perror_with_name (cmp
.file
[0].name
);
1443 status
= EXIT_TROUBLE
;
1445 if (0 <= cmp
.file
[1].desc
&& cmp
.file
[0].desc
!= cmp
.file
[1].desc
1446 && close (cmp
.file
[1].desc
) != 0)
1448 perror_with_name (cmp
.file
[1].name
);
1449 status
= EXIT_TROUBLE
;
1453 /* Now the comparison has been done, if no error prevented it,
1454 and STATUS is the value this function will return. */
1456 if (status
== EXIT_SUCCESS
)
1458 if (report_identical_files
&& !DIR_P (0))
1459 message ("Files %s and %s are identical\n",
1460 file_label
[0] ? file_label
[0] : cmp
.file
[0].name
,
1461 file_label
[1] ? file_label
[1] : cmp
.file
[1].name
);
1465 /* Flush stdout so that the user sees differences immediately.
1466 This can hurt performance, unfortunately. */
1467 if (fflush (stdout
) != 0)
1468 pfatal_with_name (_("standard output"));