Blame src/diff.c

Packit Service fdd496
/* diff - compare files line by line
Packit Service fdd496
Packit Service fdd496
   Copyright (C) 1988-1989, 1992-1994, 1996, 1998, 2001-2002, 2004, 2006-2007,
Packit Service fdd496
   2009-2013, 2015-2017 Free Software Foundation, Inc.
Packit Service fdd496
Packit Service fdd496
   This file is part of GNU DIFF.
Packit Service fdd496
Packit Service fdd496
   This program is free software: you can redistribute it and/or modify
Packit Service fdd496
   it under the terms of the GNU General Public License as published by
Packit Service fdd496
   the Free Software Foundation, either version 3 of the License, or
Packit Service fdd496
   (at your option) any later version.
Packit Service fdd496
Packit Service fdd496
   This program is distributed in the hope that it will be useful,
Packit Service fdd496
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fdd496
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service fdd496
   GNU General Public License for more details.
Packit Service fdd496
Packit Service fdd496
   You should have received a copy of the GNU General Public License
Packit Service fdd496
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service fdd496
Packit Service fdd496
#define GDIFF_MAIN
Packit Service fdd496
#include "diff.h"
Packit Service fdd496
#include "die.h"
Packit Service fdd496
#include <assert.h>
Packit Service fdd496
#include "paths.h"
Packit Service fdd496
#include <c-stack.h>
Packit Service fdd496
#include <dirname.h>
Packit Service fdd496
#include <error.h>
Packit Service fdd496
#include <exclude.h>
Packit Service fdd496
#include <exitfail.h>
Packit Service fdd496
#include <filenamecat.h>
Packit Service fdd496
#include <file-type.h>
Packit Service fdd496
#include <fnmatch.h>
Packit Service fdd496
#include <getopt.h>
Packit Service fdd496
#include <hard-locale.h>
Packit Service fdd496
#include <prepargs.h>
Packit Service fdd496
#include <progname.h>
Packit Service fdd496
#include <sh-quote.h>
Packit Service fdd496
#include <stat-time.h>
Packit Service fdd496
#include <timespec.h>
Packit Service fdd496
#include <version-etc.h>
Packit Service fdd496
#include <xalloc.h>
Packit Service fdd496
#include <xreadlink.h>
Packit Service fdd496
#include <binary-io.h>
Packit Service fdd496
Packit Service fdd496
/* The official name of this program (e.g., no 'g' prefix).  */
Packit Service fdd496
#define PROGRAM_NAME "diff"
Packit Service fdd496
Packit Service fdd496
#define AUTHORS \
Packit Service fdd496
  proper_name ("Paul Eggert"), \
Packit Service fdd496
  proper_name ("Mike Haertel"), \
Packit Service fdd496
  proper_name ("David Hayes"), \
Packit Service fdd496
  proper_name ("Richard Stallman"), \
Packit Service fdd496
  proper_name ("Len Tower")
Packit Service fdd496
Packit Service fdd496
#ifndef GUTTER_WIDTH_MINIMUM
Packit Service fdd496
# define GUTTER_WIDTH_MINIMUM 3
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
struct regexp_list
Packit Service fdd496
{
Packit Service fdd496
  char *regexps;	/* chars representing disjunction of the regexps */
Packit Service fdd496
  size_t len;		/* chars used in 'regexps' */
Packit Service fdd496
  size_t size;		/* size malloc'ed for 'regexps'; 0 if not malloc'ed */
Packit Service fdd496
  bool multiple_regexps;/* Does 'regexps' represent a disjunction?  */
Packit Service fdd496
  struct re_pattern_buffer *buf;
Packit Service fdd496
};
Packit Service fdd496
Packit Service fdd496
static int compare_files (struct comparison const *, char const *, char const *);
Packit Service fdd496
static void add_regexp (struct regexp_list *, char const *);
Packit Service fdd496
static void summarize_regexp_list (struct regexp_list *);
Packit Service fdd496
static void specify_style (enum output_style);
Packit Service fdd496
static void specify_value (char const **, char const *, char const *);
Packit Service fdd496
static void specify_colors_style (char const *);
Packit Service fdd496
static void try_help (char const *, char const *) __attribute__((noreturn));
Packit Service fdd496
static void check_stdout (void);
Packit Service fdd496
static void usage (void);
Packit Service fdd496
Packit Service 1d0110
bool (*lines_differ) (char const *, size_t, char const *, size_t);
Packit Service 1d0110
Packit Service fdd496
/* If comparing directories, compare their common subdirectories
Packit Service fdd496
   recursively.  */
Packit Service fdd496
static bool recursive;
Packit Service fdd496
Packit Service fdd496
/* In context diffs, show previous lines that match these regexps.  */
Packit Service fdd496
static struct regexp_list function_regexp_list;
Packit Service fdd496
Packit Service fdd496
/* Ignore changes affecting only lines that match these regexps.  */
Packit Service fdd496
static struct regexp_list ignore_regexp_list;
Packit Service fdd496
Packit Service fdd496
#if O_BINARY
Packit Service fdd496
/* Use binary I/O when reading and writing data (--binary).
Packit Service fdd496
   On POSIX hosts, this has no effect.  */
Packit Service fdd496
static bool binary;
Packit Service fdd496
#else
Packit Service fdd496
enum { binary = true };
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/* If one file is missing, treat it as present but empty (-N).  */
Packit Service fdd496
static bool new_file;
Packit Service fdd496
Packit Service fdd496
/* If the first file is missing, treat it as present but empty
Packit Service fdd496
   (--unidirectional-new-file).  */
Packit Service fdd496
static bool unidirectional_new_file;
Packit Service fdd496
Packit Service fdd496
/* Report files compared that are the same (-s).
Packit Service fdd496
   Normally nothing is output when that happens.  */
Packit Service fdd496
static bool report_identical_files;
Packit Service fdd496

Packit Service fdd496
static char const shortopts[] =
Packit Service fdd496
"0123456789abBcC:dD:eEfF:hHiI:lL:nNpPqrsS:tTuU:vwW:x:X:yZ";
Packit Service fdd496
Packit Service fdd496
/* Values for long options that do not have single-letter equivalents.  */
Packit Service fdd496
enum
Packit Service fdd496
{
Packit Service fdd496
  BINARY_OPTION = CHAR_MAX + 1,
Packit Service fdd496
  FROM_FILE_OPTION,
Packit Service fdd496
  HELP_OPTION,
Packit Service fdd496
  HORIZON_LINES_OPTION,
Packit Service fdd496
  IGNORE_FILE_NAME_CASE_OPTION,
Packit Service fdd496
  INHIBIT_HUNK_MERGE_OPTION,
Packit Service fdd496
  LEFT_COLUMN_OPTION,
Packit Service fdd496
  LINE_FORMAT_OPTION,
Packit Service fdd496
  NO_DEREFERENCE_OPTION,
Packit Service fdd496
  NO_IGNORE_FILE_NAME_CASE_OPTION,
Packit Service fdd496
  NORMAL_OPTION,
Packit Service fdd496
  SDIFF_MERGE_ASSIST_OPTION,
Packit Service fdd496
  STRIP_TRAILING_CR_OPTION,
Packit Service fdd496
  SUPPRESS_BLANK_EMPTY_OPTION,
Packit Service fdd496
  SUPPRESS_COMMON_LINES_OPTION,
Packit Service fdd496
  TABSIZE_OPTION,
Packit Service fdd496
  TO_FILE_OPTION,
Packit Service fdd496
Packit Service fdd496
  /* These options must be in sequence.  */
Packit Service fdd496
  UNCHANGED_LINE_FORMAT_OPTION,
Packit Service fdd496
  OLD_LINE_FORMAT_OPTION,
Packit Service fdd496
  NEW_LINE_FORMAT_OPTION,
Packit Service fdd496
Packit Service fdd496
  /* These options must be in sequence.  */
Packit Service fdd496
  UNCHANGED_GROUP_FORMAT_OPTION,
Packit Service fdd496
  OLD_GROUP_FORMAT_OPTION,
Packit Service fdd496
  NEW_GROUP_FORMAT_OPTION,
Packit Service fdd496
  CHANGED_GROUP_FORMAT_OPTION,
Packit Service fdd496
Packit Service fdd496
  COLOR_OPTION,
Packit Service fdd496
  COLOR_PALETTE_OPTION,
Packit Service fdd496
Packit Service fdd496
  PRESUME_OUTPUT_TTY_OPTION,
Packit Service fdd496
};
Packit Service fdd496
Packit Service fdd496
static char const group_format_option[][sizeof "--unchanged-group-format"] =
Packit Service fdd496
  {
Packit Service fdd496
    "--unchanged-group-format",
Packit Service fdd496
    "--old-group-format",
Packit Service fdd496
    "--new-group-format",
Packit Service fdd496
    "--changed-group-format"
Packit Service fdd496
  };
Packit Service fdd496
Packit Service fdd496
static char const line_format_option[][sizeof "--unchanged-line-format"] =
Packit Service fdd496
  {
Packit Service fdd496
    "--unchanged-line-format",
Packit Service fdd496
    "--old-line-format",
Packit Service fdd496
    "--new-line-format"
Packit Service fdd496
  };
Packit Service fdd496
Packit Service fdd496
static struct option const longopts[] =
Packit Service fdd496
{
Packit Service fdd496
  {"binary", 0, 0, BINARY_OPTION},
Packit Service fdd496
  {"brief", 0, 0, 'q'},
Packit Service fdd496
  {"changed-group-format", 1, 0, CHANGED_GROUP_FORMAT_OPTION},
Packit Service fdd496
  {"color", 2, 0, COLOR_OPTION},
Packit Service fdd496
  {"context", 2, 0, 'C'},
Packit Service fdd496
  {"ed", 0, 0, 'e'},
Packit Service fdd496
  {"exclude", 1, 0, 'x'},
Packit Service fdd496
  {"exclude-from", 1, 0, 'X'},
Packit Service fdd496
  {"expand-tabs", 0, 0, 't'},
Packit Service fdd496
  {"forward-ed", 0, 0, 'f'},
Packit Service fdd496
  {"from-file", 1, 0, FROM_FILE_OPTION},
Packit Service fdd496
  {"help", 0, 0, HELP_OPTION},
Packit Service fdd496
  {"horizon-lines", 1, 0, HORIZON_LINES_OPTION},
Packit Service fdd496
  {"ifdef", 1, 0, 'D'},
Packit Service fdd496
  {"ignore-all-space", 0, 0, 'w'},
Packit Service fdd496
  {"ignore-blank-lines", 0, 0, 'B'},
Packit Service fdd496
  {"ignore-case", 0, 0, 'i'},
Packit Service fdd496
  {"ignore-file-name-case", 0, 0, IGNORE_FILE_NAME_CASE_OPTION},
Packit Service fdd496
  {"ignore-matching-lines", 1, 0, 'I'},
Packit Service fdd496
  {"ignore-space-change", 0, 0, 'b'},
Packit Service fdd496
  {"ignore-tab-expansion", 0, 0, 'E'},
Packit Service fdd496
  {"ignore-trailing-space", 0, 0, 'Z'},
Packit Service fdd496
  {"inhibit-hunk-merge", 0, 0, INHIBIT_HUNK_MERGE_OPTION},
Packit Service fdd496
  {"initial-tab", 0, 0, 'T'},
Packit Service fdd496
  {"label", 1, 0, 'L'},
Packit Service fdd496
  {"left-column", 0, 0, LEFT_COLUMN_OPTION},
Packit Service fdd496
  {"line-format", 1, 0, LINE_FORMAT_OPTION},
Packit Service fdd496
  {"minimal", 0, 0, 'd'},
Packit Service fdd496
  {"new-file", 0, 0, 'N'},
Packit Service fdd496
  {"new-group-format", 1, 0, NEW_GROUP_FORMAT_OPTION},
Packit Service fdd496
  {"new-line-format", 1, 0, NEW_LINE_FORMAT_OPTION},
Packit Service fdd496
  {"no-dereference", 0, 0, NO_DEREFERENCE_OPTION},
Packit Service fdd496
  {"no-ignore-file-name-case", 0, 0, NO_IGNORE_FILE_NAME_CASE_OPTION},
Packit Service fdd496
  {"normal", 0, 0, NORMAL_OPTION},
Packit Service fdd496
  {"old-group-format", 1, 0, OLD_GROUP_FORMAT_OPTION},
Packit Service fdd496
  {"old-line-format", 1, 0, OLD_LINE_FORMAT_OPTION},
Packit Service fdd496
  {"paginate", 0, 0, 'l'},
Packit Service fdd496
  {"palette", 1, 0, COLOR_PALETTE_OPTION},
Packit Service fdd496
  {"rcs", 0, 0, 'n'},
Packit Service fdd496
  {"recursive", 0, 0, 'r'},
Packit Service fdd496
  {"report-identical-files", 0, 0, 's'},
Packit Service fdd496
  {"sdiff-merge-assist", 0, 0, SDIFF_MERGE_ASSIST_OPTION},
Packit Service fdd496
  {"show-c-function", 0, 0, 'p'},
Packit Service fdd496
  {"show-function-line", 1, 0, 'F'},
Packit Service fdd496
  {"side-by-side", 0, 0, 'y'},
Packit Service fdd496
  {"speed-large-files", 0, 0, 'H'},
Packit Service fdd496
  {"starting-file", 1, 0, 'S'},
Packit Service fdd496
  {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},
Packit Service fdd496
  {"suppress-blank-empty", 0, 0, SUPPRESS_BLANK_EMPTY_OPTION},
Packit Service fdd496
  {"suppress-common-lines", 0, 0, SUPPRESS_COMMON_LINES_OPTION},
Packit Service fdd496
  {"tabsize", 1, 0, TABSIZE_OPTION},
Packit Service fdd496
  {"text", 0, 0, 'a'},
Packit Service fdd496
  {"to-file", 1, 0, TO_FILE_OPTION},
Packit Service fdd496
  {"unchanged-group-format", 1, 0, UNCHANGED_GROUP_FORMAT_OPTION},
Packit Service fdd496
  {"unchanged-line-format", 1, 0, UNCHANGED_LINE_FORMAT_OPTION},
Packit Service fdd496
  {"unidirectional-new-file", 0, 0, 'P'},
Packit Service fdd496
  {"unified", 2, 0, 'U'},
Packit Service fdd496
  {"version", 0, 0, 'v'},
Packit Service fdd496
  {"width", 1, 0, 'W'},
Packit Service fdd496
Packit Service fdd496
  /* This is solely for testing.  Do not document.  */
Packit Service fdd496
  {"-presume-output-tty", no_argument, NULL, PRESUME_OUTPUT_TTY_OPTION},
Packit Service fdd496
  {0, 0, 0, 0}
Packit Service fdd496
};
Packit Service fdd496
Packit Service fdd496
/* Return a string containing the command options with which diff was invoked.
Packit Service fdd496
   Spaces appear between what were separate ARGV-elements.
Packit Service fdd496
   There is a space at the beginning but none at the end.
Packit Service fdd496
   If there were no options, the result is an empty string.
Packit Service fdd496
Packit Service fdd496
   Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT,
Packit Service fdd496
   the length of that vector.  */
Packit Service fdd496
Packit Service fdd496
static char *
Packit Service fdd496
option_list (char **optionvec, int count)
Packit Service fdd496
{
Packit Service fdd496
  int i;
Packit Service fdd496
  size_t size = 1;
Packit Service fdd496
  char *result;
Packit Service fdd496
  char *p;
Packit Service fdd496
Packit Service fdd496
  for (i = 0; i < count; i++)
Packit Service fdd496
    size += 1 + shell_quote_length (optionvec[i]);
Packit Service fdd496
Packit Service fdd496
  p = result = xmalloc (size);
Packit Service fdd496
Packit Service fdd496
  for (i = 0; i < count; i++)
Packit Service fdd496
    {
Packit Service fdd496
      *p++ = ' ';
Packit Service fdd496
      p = shell_quote_copy (p, optionvec[i]);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  *p = '\0';
Packit Service fdd496
  return result;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Return an option value suitable for add_exclude.  */
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
exclude_options (void)
Packit Service fdd496
{
Packit Service fdd496
  return EXCLUDE_WILDCARDS | (ignore_file_name_case ? FNM_CASEFOLD : 0);
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
int
Packit Service fdd496
main (int argc, char **argv)
Packit Service fdd496
{
Packit Service fdd496
  int exit_status = EXIT_SUCCESS;
Packit Service fdd496
  int c;
Packit Service fdd496
  int i;
Packit Service fdd496
  int prev = -1;
Packit Service fdd496
  lin ocontext = -1;
Packit Service fdd496
  bool explicit_context = false;
Packit Service fdd496
  size_t width = 0;
Packit Service fdd496
  bool show_c_function = false;
Packit Service fdd496
  char const *from_file = NULL;
Packit Service fdd496
  char const *to_file = NULL;
Packit Service fdd496
  uintmax_t numval;
Packit Service fdd496
  char *numend;
Packit Service fdd496
Packit Service fdd496
  /* Do our initializations.  */
Packit Service fdd496
  exit_failure = EXIT_TROUBLE;
Packit Service fdd496
  initialize_main (&argc, &argv);
Packit Service fdd496
  set_program_name (argv[0]);
Packit Service fdd496
  setlocale (LC_ALL, "");
Packit Service fdd496
  bindtextdomain (PACKAGE, LOCALEDIR);
Packit Service fdd496
  textdomain (PACKAGE);
Packit Service fdd496
  c_stack_action (0);
Packit Service fdd496
  function_regexp_list.buf = &function_regexp;
Packit Service fdd496
  ignore_regexp_list.buf = &ignore_regexp;
Packit Service fdd496
  re_set_syntax (RE_SYNTAX_GREP | RE_NO_POSIX_BACKTRACKING);
Packit Service fdd496
  excluded = new_exclude ();
Packit Service fdd496
  presume_output_tty = false;
Packit Service fdd496
Packit Service 1d0110
#ifdef HANDLE_MULTIBYTE
Packit Service 1d0110
  if (MB_CUR_MAX > 1)
Packit Service 1d0110
    lines_differ = lines_differ_multibyte;
Packit Service 1d0110
  else
Packit Service 1d0110
#endif
Packit Service 1d0110
    lines_differ = lines_differ_singlebyte;
Packit Service 1d0110
Packit Service fdd496
  /* Decode the options.  */
Packit Service fdd496
Packit Service fdd496
  while ((c = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
Packit Service fdd496
    {
Packit Service fdd496
      switch (c)
Packit Service fdd496
	{
Packit Service fdd496
	case 0:
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case '0':
Packit Service fdd496
	case '1':
Packit Service fdd496
	case '2':
Packit Service fdd496
	case '3':
Packit Service fdd496
	case '4':
Packit Service fdd496
	case '5':
Packit Service fdd496
	case '6':
Packit Service fdd496
	case '7':
Packit Service fdd496
	case '8':
Packit Service fdd496
	case '9':
Packit Service fdd496
	  ocontext = (! ISDIGIT (prev)
Packit Service fdd496
		      ? c - '0'
Packit Service fdd496
		      : (ocontext - (c - '0' <= CONTEXT_MAX % 10)
Packit Service fdd496
			 < CONTEXT_MAX / 10)
Packit Service fdd496
		      ? 10 * ocontext + (c - '0')
Packit Service fdd496
		      : CONTEXT_MAX);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'a':
Packit Service fdd496
	  text = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'b':
Packit Service fdd496
	  if (ignore_white_space < IGNORE_SPACE_CHANGE)
Packit Service fdd496
	    ignore_white_space = IGNORE_SPACE_CHANGE;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'Z':
Packit Service fdd496
	  if (ignore_white_space < IGNORE_SPACE_CHANGE)
Packit Service fdd496
	    ignore_white_space |= IGNORE_TRAILING_SPACE;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'B':
Packit Service fdd496
	  ignore_blank_lines = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'C':
Packit Service fdd496
	case 'U':
Packit Service fdd496
	  {
Packit Service fdd496
	    if (optarg)
Packit Service fdd496
	      {
Packit Service fdd496
		numval = strtoumax (optarg, &numend, 10);
Packit Service fdd496
		if (*numend)
Packit Service fdd496
		  try_help ("invalid context length '%s'", optarg);
Packit Service fdd496
		if (CONTEXT_MAX < numval)
Packit Service fdd496
		  numval = CONTEXT_MAX;
Packit Service fdd496
	      }
Packit Service fdd496
	    else
Packit Service fdd496
	      numval = 3;
Packit Service fdd496
Packit Service fdd496
	    specify_style (c == 'U' ? OUTPUT_UNIFIED : OUTPUT_CONTEXT);
Packit Service fdd496
	    if (context < numval)
Packit Service fdd496
	      context = numval;
Packit Service fdd496
	    explicit_context = true;
Packit Service fdd496
	  }
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'c':
Packit Service fdd496
	  specify_style (OUTPUT_CONTEXT);
Packit Service fdd496
	  if (context < 3)
Packit Service fdd496
	    context = 3;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'd':
Packit Service fdd496
	  minimal = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'D':
Packit Service fdd496
	  specify_style (OUTPUT_IFDEF);
Packit Service fdd496
	  {
Packit Service fdd496
	    static char const C_ifdef_group_formats[] =
Packit Service fdd496
	      "%%=%c#ifndef %s\n%%<#endif /* ! %s */\n%c#ifdef %s\n%%>#endif /* %s */\n%c#ifndef %s\n%%<#else /* %s */\n%%>#endif /* %s */\n";
Packit Service fdd496
	    char *b = xmalloc (sizeof C_ifdef_group_formats
Packit Service fdd496
			       + 7 * strlen (optarg) - 14 /* 7*"%s" */
Packit Service fdd496
			       - 8 /* 5*"%%" + 3*"%c" */);
Packit Service fdd496
	    sprintf (b, C_ifdef_group_formats,
Packit Service fdd496
		     0,
Packit Service fdd496
		     optarg, optarg, 0,
Packit Service fdd496
		     optarg, optarg, 0,
Packit Service fdd496
		     optarg, optarg, optarg);
Packit Service fdd496
	    for (i = 0; i < sizeof group_format / sizeof group_format[0]; i++)
Packit Service fdd496
	      {
Packit Service fdd496
		specify_value (&group_format[i], b, "-D");
Packit Service fdd496
		b += strlen (b) + 1;
Packit Service fdd496
	      }
Packit Service fdd496
	  }
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'e':
Packit Service fdd496
	  specify_style (OUTPUT_ED);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'E':
Packit Service fdd496
	  if (ignore_white_space < IGNORE_SPACE_CHANGE)
Packit Service fdd496
	    ignore_white_space |= IGNORE_TAB_EXPANSION;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'f':
Packit Service fdd496
	  specify_style (OUTPUT_FORWARD_ED);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'F':
Packit Service fdd496
	  add_regexp (&function_regexp_list, optarg);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'h':
Packit Service fdd496
	  /* Split the files into chunks for faster processing.
Packit Service fdd496
	     Usually does not change the result.
Packit Service fdd496
Packit Service fdd496
	     This currently has no effect.  */
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'H':
Packit Service fdd496
	  speed_large_files = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'i':
Packit Service fdd496
	  ignore_case = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'I':
Packit Service fdd496
	  add_regexp (&ignore_regexp_list, optarg);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'l':
Packit Service fdd496
	  if (!pr_program[0])
Packit Service fdd496
	    try_help ("pagination not supported on this host", NULL);
Packit Service fdd496
	  paginate = true;
Packit Service fdd496
#ifdef SIGCHLD
Packit Service fdd496
	  /* Pagination requires forking and waiting, and
Packit Service fdd496
	     System V fork+wait does not work if SIGCHLD is ignored.  */
Packit Service fdd496
	  signal (SIGCHLD, SIG_DFL);
Packit Service fdd496
#endif
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'L':
Packit Service fdd496
	  if (!file_label[0])
Packit Service fdd496
	    file_label[0] = optarg;
Packit Service fdd496
	  else if (!file_label[1])
Packit Service fdd496
	    file_label[1] = optarg;
Packit Service fdd496
	  else
Packit Service fdd496
	    fatal ("too many file label options");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'n':
Packit Service fdd496
	  specify_style (OUTPUT_RCS);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'N':
Packit Service fdd496
	  new_file = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'p':
Packit Service fdd496
	  show_c_function = true;
Packit Service fdd496
	  add_regexp (&function_regexp_list, "^[[:alpha:]$_]");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'P':
Packit Service fdd496
	  unidirectional_new_file = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'q':
Packit Service fdd496
	  brief = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'r':
Packit Service fdd496
	  recursive = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 's':
Packit Service fdd496
	  report_identical_files = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'S':
Packit Service fdd496
	  specify_value (&starting_file, optarg, "-S");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 't':
Packit Service fdd496
	  expand_tabs = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'T':
Packit Service fdd496
	  initial_tab = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'u':
Packit Service fdd496
	  specify_style (OUTPUT_UNIFIED);
Packit Service fdd496
	  if (context < 3)
Packit Service fdd496
	    context = 3;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'v':
Packit Service fdd496
	  version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version,
Packit Service fdd496
		       AUTHORS, (char *) NULL);
Packit Service fdd496
	  check_stdout ();
Packit Service fdd496
	  return EXIT_SUCCESS;
Packit Service fdd496
Packit Service fdd496
	case 'w':
Packit Service fdd496
	  ignore_white_space = IGNORE_ALL_SPACE;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'x':
Packit Service fdd496
	  add_exclude (excluded, optarg, exclude_options ());
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'X':
Packit Service fdd496
	  if (add_exclude_file (add_exclude, excluded, optarg,
Packit Service fdd496
				exclude_options (), '\n'))
Packit Service fdd496
	    pfatal_with_name (optarg);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'y':
Packit Service fdd496
	  specify_style (OUTPUT_SDIFF);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'W':
Packit Service fdd496
	  numval = strtoumax (optarg, &numend, 10);
Packit Service fdd496
	  if (! (0 < numval && numval <= SIZE_MAX) || *numend)
Packit Service fdd496
	    try_help ("invalid width '%s'", optarg);
Packit Service fdd496
	  if (width != numval)
Packit Service fdd496
	    {
Packit Service fdd496
	      if (width)
Packit Service fdd496
		fatal ("conflicting width options");
Packit Service fdd496
	      width = numval;
Packit Service fdd496
	    }
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case BINARY_OPTION:
Packit Service fdd496
#if O_BINARY
Packit Service fdd496
	  binary = true;
Packit Service fdd496
	  if (! isatty (STDOUT_FILENO))
Packit Service fdd496
	    set_binary_mode (STDOUT_FILENO, O_BINARY);
Packit Service fdd496
#endif
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case FROM_FILE_OPTION:
Packit Service fdd496
	  specify_value (&from_file, optarg, "--from-file");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case HELP_OPTION:
Packit Service fdd496
	  usage ();
Packit Service fdd496
	  check_stdout ();
Packit Service fdd496
	  return EXIT_SUCCESS;
Packit Service fdd496
Packit Service fdd496
	case HORIZON_LINES_OPTION:
Packit Service fdd496
	  numval = strtoumax (optarg, &numend, 10);
Packit Service fdd496
	  if (*numend)
Packit Service fdd496
	    try_help ("invalid horizon length '%s'", optarg);
Packit Service fdd496
	  horizon_lines = MAX (horizon_lines, MIN (numval, LIN_MAX));
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case IGNORE_FILE_NAME_CASE_OPTION:
Packit Service fdd496
	  ignore_file_name_case = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case INHIBIT_HUNK_MERGE_OPTION:
Packit Service fdd496
	  /* This option is obsolete, but accept it for backward
Packit Service fdd496
             compatibility.  */
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case LEFT_COLUMN_OPTION:
Packit Service fdd496
	  left_column = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case LINE_FORMAT_OPTION:
Packit Service fdd496
	  specify_style (OUTPUT_IFDEF);
Packit Service fdd496
	  for (i = 0; i < sizeof line_format / sizeof line_format[0]; i++)
Packit Service fdd496
	    specify_value (&line_format[i], optarg, "--line-format");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case NO_DEREFERENCE_OPTION:
Packit Service fdd496
	  no_dereference_symlinks = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case NO_IGNORE_FILE_NAME_CASE_OPTION:
Packit Service fdd496
	  ignore_file_name_case = false;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case NORMAL_OPTION:
Packit Service fdd496
	  specify_style (OUTPUT_NORMAL);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case SDIFF_MERGE_ASSIST_OPTION:
Packit Service fdd496
	  specify_style (OUTPUT_SDIFF);
Packit Service fdd496
	  sdiff_merge_assist = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case STRIP_TRAILING_CR_OPTION:
Packit Service fdd496
	  strip_trailing_cr = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case SUPPRESS_BLANK_EMPTY_OPTION:
Packit Service fdd496
	  suppress_blank_empty = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case SUPPRESS_COMMON_LINES_OPTION:
Packit Service fdd496
	  suppress_common_lines = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case TABSIZE_OPTION:
Packit Service fdd496
	  numval = strtoumax (optarg, &numend, 10);
Packit Service fdd496
	  if (! (0 < numval && numval <= SIZE_MAX - GUTTER_WIDTH_MINIMUM)
Packit Service fdd496
	      || *numend)
Packit Service fdd496
	    try_help ("invalid tabsize '%s'", optarg);
Packit Service fdd496
	  if (tabsize != numval)
Packit Service fdd496
	    {
Packit Service fdd496
	      if (tabsize)
Packit Service fdd496
		fatal ("conflicting tabsize options");
Packit Service fdd496
	      tabsize = numval;
Packit Service fdd496
	    }
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case TO_FILE_OPTION:
Packit Service fdd496
	  specify_value (&to_file, optarg, "--to-file");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case UNCHANGED_LINE_FORMAT_OPTION:
Packit Service fdd496
	case OLD_LINE_FORMAT_OPTION:
Packit Service fdd496
	case NEW_LINE_FORMAT_OPTION:
Packit Service fdd496
	  specify_style (OUTPUT_IFDEF);
Packit Service fdd496
	  c -= UNCHANGED_LINE_FORMAT_OPTION;
Packit Service fdd496
	  specify_value (&line_format[c], optarg, line_format_option[c]);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case UNCHANGED_GROUP_FORMAT_OPTION:
Packit Service fdd496
	case OLD_GROUP_FORMAT_OPTION:
Packit Service fdd496
	case NEW_GROUP_FORMAT_OPTION:
Packit Service fdd496
	case CHANGED_GROUP_FORMAT_OPTION:
Packit Service fdd496
	  specify_style (OUTPUT_IFDEF);
Packit Service fdd496
	  c -= UNCHANGED_GROUP_FORMAT_OPTION;
Packit Service fdd496
	  specify_value (&group_format[c], optarg, group_format_option[c]);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case COLOR_OPTION:
Packit Service fdd496
	  specify_colors_style (optarg);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case COLOR_PALETTE_OPTION:
Packit Service fdd496
	  set_color_palette (optarg);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
        case PRESUME_OUTPUT_TTY_OPTION:
Packit Service fdd496
          presume_output_tty = true;
Packit Service fdd496
          break;
Packit Service fdd496
Packit Service fdd496
	default:
Packit Service fdd496
	  try_help (NULL, NULL);
Packit Service fdd496
	}
Packit Service fdd496
      prev = c;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  if (colors_style == AUTO)
Packit Service fdd496
    {
Packit Service fdd496
      char const *t = getenv ("TERM");
Packit Service fdd496
      if (t && STREQ (t, "dumb"))
Packit Service fdd496
        colors_style = NEVER;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  if (output_style == OUTPUT_UNSPECIFIED)
Packit Service fdd496
    {
Packit Service fdd496
      if (show_c_function)
Packit Service fdd496
	{
Packit Service fdd496
	  specify_style (OUTPUT_CONTEXT);
Packit Service fdd496
	  if (ocontext < 0)
Packit Service fdd496
	    context = 3;
Packit Service fdd496
	}
Packit Service fdd496
      else
Packit Service fdd496
	specify_style (OUTPUT_NORMAL);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  if (output_style != OUTPUT_CONTEXT || hard_locale (LC_TIME))
Packit Service fdd496
    {
Packit Service fdd496
#if (defined STAT_TIMESPEC || defined STAT_TIMESPEC_NS \
Packit Service fdd496
     || defined HAVE_STRUCT_STAT_ST_SPARE1)
Packit Service fdd496
      time_format = "%Y-%m-%d %H:%M:%S.%N %z";
Packit Service fdd496
#else
Packit Service fdd496
      time_format = "%Y-%m-%d %H:%M:%S %z";
Packit Service fdd496
#endif
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      /* See POSIX 1003.1-2001 for this format.  */
Packit Service fdd496
      time_format = "%a %b %e %T %Y";
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  if (0 <= ocontext
Packit Service fdd496
      && (output_style == OUTPUT_CONTEXT
Packit Service fdd496
	  || output_style == OUTPUT_UNIFIED)
Packit Service fdd496
      && (context < ocontext
Packit Service fdd496
	  || (ocontext < context && ! explicit_context)))
Packit Service fdd496
    context = ocontext;
Packit Service fdd496
Packit Service fdd496
  if (! tabsize)
Packit Service fdd496
    tabsize = 8;
Packit Service fdd496
  if (! width)
Packit Service fdd496
    width = 130;
Packit Service fdd496
Packit Service fdd496
  {
Packit Service fdd496
    /* Maximize first the half line width, and then the gutter width,
Packit Service fdd496
       according to the following constraints:
Packit Service fdd496
Packit Service fdd496
	1.  Two half lines plus a gutter must fit in a line.
Packit Service fdd496
	2.  If the half line width is nonzero:
Packit Service fdd496
	    a.  The gutter width is at least GUTTER_WIDTH_MINIMUM.
Packit Service fdd496
	    b.  If tabs are not expanded to spaces,
Packit Service fdd496
		a half line plus a gutter is an integral number of tabs,
Packit Service fdd496
		so that tabs in the right column line up.  */
Packit Service fdd496
Packit Service fdd496
    size_t t = expand_tabs ? 1 : tabsize;
Packit Service fdd496
    size_t w = width;
Packit Service fdd496
    size_t t_plus_g = t + GUTTER_WIDTH_MINIMUM;
Packit Service fdd496
    size_t unaligned_off = (w >> 1) + (t_plus_g >> 1) + (w & t_plus_g & 1);
Packit Service fdd496
    size_t off = unaligned_off - unaligned_off % t;
Packit Service fdd496
    sdiff_half_width = (off <= GUTTER_WIDTH_MINIMUM || w <= off
Packit Service fdd496
			? 0
Packit Service fdd496
			: MIN (off - GUTTER_WIDTH_MINIMUM, w - off));
Packit Service fdd496
    sdiff_column2_offset = sdiff_half_width ? off : w;
Packit Service fdd496
  }
Packit Service fdd496
Packit Service fdd496
  /* Make the horizon at least as large as the context, so that
Packit Service fdd496
     shift_boundaries has more freedom to shift the first and last hunks.  */
Packit Service fdd496
  if (horizon_lines < context)
Packit Service fdd496
    horizon_lines = context;
Packit Service fdd496
Packit Service fdd496
  summarize_regexp_list (&function_regexp_list);
Packit Service fdd496
  summarize_regexp_list (&ignore_regexp_list);
Packit Service fdd496
Packit Service fdd496
  if (output_style == OUTPUT_IFDEF)
Packit Service fdd496
    {
Packit Service fdd496
      for (i = 0; i < sizeof line_format / sizeof line_format[0]; i++)
Packit Service fdd496
	if (!line_format[i])
Packit Service fdd496
	  line_format[i] = "%l\n";
Packit Service fdd496
      if (!group_format[OLD])
Packit Service fdd496
	group_format[OLD]
Packit Service fdd496
	  = group_format[CHANGED] ? group_format[CHANGED] : "%<";
Packit Service fdd496
      if (!group_format[NEW])
Packit Service fdd496
	group_format[NEW]
Packit Service fdd496
	  = group_format[CHANGED] ? group_format[CHANGED] : "%>";
Packit Service fdd496
      if (!group_format[UNCHANGED])
Packit Service fdd496
	group_format[UNCHANGED] = "%=";
Packit Service fdd496
      if (!group_format[CHANGED])
Packit Service fdd496
	group_format[CHANGED] = concat (group_format[OLD],
Packit Service fdd496
					group_format[NEW], "");
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  no_diff_means_no_output =
Packit Service fdd496
    (output_style == OUTPUT_IFDEF ?
Packit Service fdd496
      (!*group_format[UNCHANGED]
Packit Service fdd496
       || (STREQ (group_format[UNCHANGED], "%=")
Packit Service fdd496
	   && !*line_format[UNCHANGED]))
Packit Service fdd496
     : (output_style != OUTPUT_SDIFF) | suppress_common_lines);
Packit Service fdd496
Packit Service fdd496
  files_can_be_treated_as_binary =
Packit Service fdd496
    (brief & binary
Packit Service fdd496
     & ~ (ignore_blank_lines | ignore_case | strip_trailing_cr
Packit Service fdd496
	  | (ignore_regexp_list.regexps || ignore_white_space)));
Packit Service fdd496
Packit Service fdd496
  switch_string = option_list (argv + 1, optind - 1);
Packit Service fdd496
Packit Service fdd496
  if (from_file)
Packit Service fdd496
    {
Packit Service fdd496
      if (to_file)
Packit Service fdd496
	fatal ("--from-file and --to-file both specified");
Packit Service fdd496
      else
Packit Service fdd496
	for (; optind < argc; optind++)
Packit Service fdd496
	  {
Packit Service fdd496
	    int status = compare_files (NULL, from_file, argv[optind]);
Packit Service fdd496
	    if (exit_status < status)
Packit Service fdd496
	      exit_status = status;
Packit Service fdd496
	  }
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      if (to_file)
Packit Service fdd496
	for (; optind < argc; optind++)
Packit Service fdd496
	  {
Packit Service fdd496
	    int status = compare_files (NULL, argv[optind], to_file);
Packit Service fdd496
	    if (exit_status < status)
Packit Service fdd496
	      exit_status = status;
Packit Service fdd496
	  }
Packit Service fdd496
      else
Packit Service fdd496
	{
Packit Service fdd496
	  if (argc - optind != 2)
Packit Service fdd496
	    {
Packit Service fdd496
	      if (argc - optind < 2)
Packit Service fdd496
		try_help ("missing operand after '%s'", argv[argc - 1]);
Packit Service fdd496
	      else
Packit Service fdd496
		try_help ("extra operand '%s'", argv[optind + 2]);
Packit Service fdd496
	    }
Packit Service fdd496
Packit Service fdd496
	  exit_status = compare_files (NULL, argv[optind], argv[optind + 1]);
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  /* Print any messages that were saved up for last.  */
Packit Service fdd496
  print_message_queue ();
Packit Service fdd496
Packit Service fdd496
  check_stdout ();
Packit Service fdd496
  exit (exit_status);
Packit Service fdd496
  return exit_status;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Append to REGLIST the regexp PATTERN.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
add_regexp (struct regexp_list *reglist, char const *pattern)
Packit Service fdd496
{
Packit Service fdd496
  size_t patlen = strlen (pattern);
Packit Service fdd496
  char const *m = re_compile_pattern (pattern, patlen, reglist->buf);
Packit Service fdd496
Packit Service fdd496
  if (m != 0)
Packit Service fdd496
    error (EXIT_TROUBLE, 0, "%s: %s", pattern, m);
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      char *regexps = reglist->regexps;
Packit Service fdd496
      size_t len = reglist->len;
Packit Service fdd496
      bool multiple_regexps = reglist->multiple_regexps = regexps != 0;
Packit Service fdd496
      size_t newlen = reglist->len = len + 2 * multiple_regexps + patlen;
Packit Service fdd496
      size_t size = reglist->size;
Packit Service fdd496
Packit Service fdd496
      if (size <= newlen)
Packit Service fdd496
	{
Packit Service fdd496
	  if (!size)
Packit Service fdd496
	    size = 1;
Packit Service fdd496
Packit Service fdd496
	  do size *= 2;
Packit Service fdd496
	  while (size <= newlen);
Packit Service fdd496
Packit Service fdd496
	  reglist->size = size;
Packit Service fdd496
	  reglist->regexps = regexps = xrealloc (regexps, size);
Packit Service fdd496
	}
Packit Service fdd496
      if (multiple_regexps)
Packit Service fdd496
	{
Packit Service fdd496
	  regexps[len++] = '\\';
Packit Service fdd496
	  regexps[len++] = '|';
Packit Service fdd496
	}
Packit Service fdd496
      memcpy (regexps + len, pattern, patlen + 1);
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Ensure that REGLIST represents the disjunction of its regexps.
Packit Service fdd496
   This is done here, rather than earlier, to avoid O(N^2) behavior.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
summarize_regexp_list (struct regexp_list *reglist)
Packit Service fdd496
{
Packit Service fdd496
  if (reglist->regexps)
Packit Service fdd496
    {
Packit Service fdd496
      /* At least one regexp was specified.  Allocate a fastmap for it.  */
Packit Service fdd496
      reglist->buf->fastmap = xmalloc (1 << CHAR_BIT);
Packit Service fdd496
      if (reglist->multiple_regexps)
Packit Service fdd496
	{
Packit Service fdd496
	  /* Compile the disjunction of the regexps.
Packit Service fdd496
	     (If just one regexp was specified, it is already compiled.)  */
Packit Service fdd496
	  char const *m = re_compile_pattern (reglist->regexps, reglist->len,
Packit Service fdd496
					      reglist->buf);
Packit Service fdd496
	  if (m)
Packit Service fdd496
	    die (EXIT_TROUBLE, 0, "%s: %s", reglist->regexps, m);
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
try_help (char const *reason_msgid, char const *operand)
Packit Service fdd496
{
Packit Service fdd496
  if (reason_msgid)
Packit Service fdd496
    error (0, 0, _(reason_msgid), operand);
Packit Service fdd496
  die (EXIT_TROUBLE, 0, _("Try '%s --help' for more information."),
Packit Service fdd496
	 program_name);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
check_stdout (void)
Packit Service fdd496
{
Packit Service fdd496
  if (ferror (stdout))
Packit Service fdd496
    fatal ("write failed");
Packit Service fdd496
  else if (fclose (stdout) != 0)
Packit Service fdd496
    pfatal_with_name (_("standard output"));
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static char const * const option_help_msgid[] = {
Packit Service fdd496
  N_("    --normal                  output a normal diff (the default)"),
Packit Service fdd496
  N_("-q, --brief                   report only when files differ"),
Packit Service fdd496
  N_("-s, --report-identical-files  report when two files are the same"),
Packit Service fdd496
  N_("-c, -C NUM, --context[=NUM]   output NUM (default 3) lines of copied context"),
Packit Service fdd496
  N_("-u, -U NUM, --unified[=NUM]   output NUM (default 3) lines of unified context"),
Packit Service fdd496
  N_("-e, --ed                      output an ed script"),
Packit Service fdd496
  N_("-n, --rcs                     output an RCS format diff"),
Packit Service fdd496
  N_("-y, --side-by-side            output in two columns"),
Packit Service fdd496
  N_("-W, --width=NUM               output at most NUM (default 130) print columns"),
Packit Service fdd496
  N_("    --left-column             output only the left column of common lines"),
Packit Service fdd496
  N_("    --suppress-common-lines   do not output common lines"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("-p, --show-c-function         show which C function each change is in"),
Packit Service fdd496
  N_("-F, --show-function-line=RE   show the most recent line matching RE"),
Packit Service fdd496
  N_("    --label LABEL             use LABEL instead of file name and timestamp\n"
Packit Service fdd496
     "                                (can be repeated)"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("-t, --expand-tabs             expand tabs to spaces in output"),
Packit Service fdd496
  N_("-T, --initial-tab             make tabs line up by prepending a tab"),
Packit Service fdd496
  N_("    --tabsize=NUM             tab stops every NUM (default 8) print columns"),
Packit Service fdd496
  N_("    --suppress-blank-empty    suppress space or tab before empty output lines"),
Packit Service fdd496
  N_("-l, --paginate                pass output through 'pr' to paginate it"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("-r, --recursive                 recursively compare any subdirectories found"),
Packit Service fdd496
  N_("    --no-dereference            don't follow symbolic links"),
Packit Service fdd496
  N_("-N, --new-file                  treat absent files as empty"),
Packit Service fdd496
  N_("    --unidirectional-new-file   treat absent first files as empty"),
Packit Service fdd496
  N_("    --ignore-file-name-case     ignore case when comparing file names"),
Packit Service fdd496
  N_("    --no-ignore-file-name-case  consider case when comparing file names"),
Packit Service fdd496
  N_("-x, --exclude=PAT               exclude files that match PAT"),
Packit Service fdd496
  N_("-X, --exclude-from=FILE         exclude files that match any pattern in FILE"),
Packit Service fdd496
  N_("-S, --starting-file=FILE        start with FILE when comparing directories"),
Packit Service fdd496
  N_("    --from-file=FILE1           compare FILE1 to all operands;\n"
Packit Service fdd496
     "                                  FILE1 can be a directory"),
Packit Service fdd496
  N_("    --to-file=FILE2             compare all operands to FILE2;\n"
Packit Service fdd496
     "                                  FILE2 can be a directory"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("-i, --ignore-case               ignore case differences in file contents"),
Packit Service fdd496
  N_("-E, --ignore-tab-expansion      ignore changes due to tab expansion"),
Packit Service fdd496
  N_("-Z, --ignore-trailing-space     ignore white space at line end"),
Packit Service fdd496
  N_("-b, --ignore-space-change       ignore changes in the amount of white space"),
Packit Service fdd496
  N_("-w, --ignore-all-space          ignore all white space"),
Packit Service fdd496
  N_("-B, --ignore-blank-lines        ignore changes where lines are all blank"),
Packit Service fdd496
  N_("-I, --ignore-matching-lines=RE  ignore changes where all lines match RE"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("-a, --text                      treat all files as text"),
Packit Service fdd496
  N_("    --strip-trailing-cr         strip trailing carriage return on input"),
Packit Service fdd496
#if O_BINARY
Packit Service fdd496
  N_("    --binary                    read and write data in binary mode"),
Packit Service fdd496
#endif
Packit Service fdd496
  "",
Packit Service fdd496
  N_("-D, --ifdef=NAME                output merged file with '#ifdef NAME' diffs"),
Packit Service fdd496
  N_("    --GTYPE-group-format=GFMT   format GTYPE input groups with GFMT"),
Packit Service fdd496
  N_("    --line-format=LFMT          format all input lines with LFMT"),
Packit Service fdd496
  N_("    --LTYPE-line-format=LFMT    format LTYPE input lines with LFMT"),
Packit Service fdd496
  N_("  These format options provide fine-grained control over the output\n"
Packit Service fdd496
     "    of diff, generalizing -D/--ifdef."),
Packit Service fdd496
  N_("  LTYPE is 'old', 'new', or 'unchanged'.  GTYPE is LTYPE or 'changed'."),
Packit Service fdd496
  N_("  GFMT (only) may contain:\n\
Packit Service fdd496
    %<  lines from FILE1\n\
Packit Service fdd496
    %>  lines from FILE2\n\
Packit Service fdd496
    %=  lines common to FILE1 and FILE2\n\
Packit Service fdd496
    %[-][WIDTH][.[PREC]]{doxX}LETTER  printf-style spec for LETTER\n\
Packit Service fdd496
      LETTERs are as follows for new group, lower case for old group:\n\
Packit Service fdd496
        F  first line number\n\
Packit Service fdd496
        L  last line number\n\
Packit Service fdd496
        N  number of lines = L-F+1\n\
Packit Service fdd496
        E  F-1\n\
Packit Service fdd496
        M  L+1\n\
Packit Service fdd496
    %(A=B?T:E)  if A equals B then T else E"),
Packit Service fdd496
  N_("  LFMT (only) may contain:\n\
Packit Service fdd496
    %L  contents of line\n\
Packit Service fdd496
    %l  contents of line, excluding any trailing newline\n\
Packit Service fdd496
    %[-][WIDTH][.[PREC]]{doxX}n  printf-style spec for input line number"),
Packit Service fdd496
  N_("  Both GFMT and LFMT may contain:\n\
Packit Service fdd496
    %%  %\n\
Packit Service fdd496
    %c'C'  the single character C\n\
Packit Service fdd496
    %c'\\OOO'  the character with octal code OOO\n\
Packit Service fdd496
    C    the character C (other characters represent themselves)"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("-d, --minimal            try hard to find a smaller set of changes"),
Packit Service fdd496
  N_("    --horizon-lines=NUM  keep NUM lines of the common prefix and suffix"),
Packit Service fdd496
  N_("    --speed-large-files  assume large files and many scattered small changes"),
Packit Service fdd496
  N_("    --color[=WHEN]       colorize the output; WHEN can be 'never', 'always',\n"
Packit Service fdd496
     "                           or 'auto' (the default)"),
Packit Service fdd496
  N_("    --palette=PALETTE    the colors to use when --color is active; PALETTE is\n"
Packit Service fdd496
     "                           a colon-separated list of terminfo capabilities"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("    --help               display this help and exit"),
Packit Service fdd496
  N_("-v, --version            output version information and exit"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("FILES are 'FILE1 FILE2' or 'DIR1 DIR2' or 'DIR FILE' or 'FILE DIR'."),
Packit Service fdd496
  N_("If --from-file or --to-file is given, there are no restrictions on FILE(s)."),
Packit Service fdd496
  N_("If a FILE is '-', read standard input."),
Packit Service fdd496
  N_("Exit status is 0 if inputs are the same, 1 if different, 2 if trouble."),
Packit Service fdd496
  0
Packit Service fdd496
};
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
usage (void)
Packit Service fdd496
{
Packit Service fdd496
  char const * const *p;
Packit Service fdd496
Packit Service fdd496
  printf (_("Usage: %s [OPTION]... FILES\n"), program_name);
Packit Service fdd496
  printf ("%s\n\n", _("Compare FILES line by line."));
Packit Service fdd496
Packit Service fdd496
  fputs (_("\
Packit Service fdd496
Mandatory arguments to long options are mandatory for short options too.\n\
Packit Service fdd496
"), stdout);
Packit Service fdd496
Packit Service fdd496
  for (p = option_help_msgid;  *p;  p++)
Packit Service fdd496
    {
Packit Service fdd496
      if (!**p)
Packit Service fdd496
	putchar ('\n');
Packit Service fdd496
      else
Packit Service fdd496
	{
Packit Service fdd496
	  char const *msg = _(*p);
Packit Service fdd496
	  char const *nl;
Packit Service fdd496
	  while ((nl = strchr (msg, '\n')))
Packit Service fdd496
	    {
Packit Service fdd496
	      int msglen = nl + 1 - msg;
Packit Service fdd496
	      printf ("  %.*s", msglen, msg);
Packit Service fdd496
	      msg = nl + 1;
Packit Service fdd496
	    }
Packit Service fdd496
Packit Service fdd496
	  printf ("  %s\n" + 2 * (*msg != ' ' && *msg != '-'), msg);
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
  emit_bug_reporting_address ();
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Set VAR to VALUE, reporting an OPTION error if this is a
Packit Service fdd496
   conflict.  */
Packit Service fdd496
static void
Packit Service fdd496
specify_value (char const **var, char const *value, char const *option)
Packit Service fdd496
{
Packit Service fdd496
  if (*var && ! STREQ (*var, value))
Packit Service fdd496
    {
Packit Service fdd496
      error (0, 0, _("conflicting %s option value '%s'"), option, value);
Packit Service fdd496
      try_help (NULL, NULL);
Packit Service fdd496
    }
Packit Service fdd496
  *var = value;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Set the output style to STYLE, diagnosing conflicts.  */
Packit Service fdd496
static void
Packit Service fdd496
specify_style (enum output_style style)
Packit Service fdd496
{
Packit Service fdd496
  if (output_style != style)
Packit Service fdd496
    {
Packit Service fdd496
      if (output_style != OUTPUT_UNSPECIFIED)
Packit Service fdd496
	try_help ("conflicting output style options", NULL);
Packit Service fdd496
      output_style = style;
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Set the color mode.  */
Packit Service fdd496
static void
Packit Service fdd496
specify_colors_style (char const *value)
Packit Service fdd496
{
Packit Service fdd496
  if (value == NULL || STREQ (value, "auto"))
Packit Service fdd496
    colors_style = AUTO;
Packit Service fdd496
  else if (STREQ (value, "always"))
Packit Service fdd496
    colors_style = ALWAYS;
Packit Service fdd496
  else if (STREQ (value, "never"))
Packit Service fdd496
    colors_style = NEVER;
Packit Service fdd496
  else
Packit Service fdd496
    try_help ("invalid color '%s'", value);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496

Packit Service fdd496
/* Set the last-modified time of *ST to be the current time.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
set_mtime_to_now (struct stat *st)
Packit Service fdd496
{
Packit Service fdd496
#ifdef STAT_TIMESPEC
Packit Service fdd496
  gettime (&STAT_TIMESPEC (st, st_mtim));
Packit Service fdd496
#else
Packit Service fdd496
  struct timespec t;
Packit Service fdd496
  gettime (&t);
Packit Service fdd496
  st->st_mtime = t.tv_sec;
Packit Service fdd496
# if defined STAT_TIMESPEC_NS
Packit Service fdd496
  STAT_TIMESPEC_NS (st, st_mtim) = t.tv_nsec;
Packit Service fdd496
# elif defined HAVE_STRUCT_STAT_ST_SPARE1
Packit Service fdd496
  st->st_spare1 = t.tv_nsec / 1000;
Packit Service fdd496
# endif
Packit Service fdd496
#endif
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
/* Compare two files (or dirs) with parent comparison PARENT
Packit Service fdd496
   and names NAME0 and NAME1.
Packit Service fdd496
   (If PARENT is null, then the first name is just NAME0, etc.)
Packit Service fdd496
   This is self-contained; it opens the files and closes them.
Packit Service fdd496
Packit Service fdd496
   Value is EXIT_SUCCESS if files are the same, EXIT_FAILURE if
Packit Service fdd496
   different, EXIT_TROUBLE if there is a problem opening them.  */
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
compare_files (struct comparison const *parent,
Packit Service fdd496
	       char const *name0,
Packit Service fdd496
	       char const *name1)
Packit Service fdd496
{
Packit Service fdd496
  struct comparison cmp;
Packit Service fdd496
#define DIR_P(f) (S_ISDIR (cmp.file[f].stat.st_mode) != 0)
Packit Service fdd496
  register int f;
Packit Service fdd496
  int status = EXIT_SUCCESS;
Packit Service fdd496
  bool same_files;
Packit Service fdd496
  char *free0;
Packit Service fdd496
  char *free1;
Packit Service fdd496
Packit Service fdd496
  /* If this is directory comparison, perhaps we have a file
Packit Service fdd496
     that exists only in one of the directories.
Packit Service fdd496
     If so, just print a message to that effect.  */
Packit Service fdd496
Packit Service fdd496
  if (! ((name0 && name1)
Packit Service fdd496
	 || (unidirectional_new_file && name1)
Packit Service fdd496
	 || new_file))
Packit Service fdd496
    {
Packit Service fdd496
      char const *name = name0 ? name0 : name1;
Packit Service fdd496
      char const *dir = parent->file[!name0].name;
Packit Service fdd496
Packit Service fdd496
      /* See POSIX 1003.1-2001 for this format.  */
Packit Service fdd496
      message ("Only in %s: %s\n", dir, name);
Packit Service fdd496
Packit Service fdd496
      /* Return EXIT_FAILURE so that diff_dirs will return
Packit Service fdd496
	 EXIT_FAILURE ("some files differ").  */
Packit Service fdd496
      return EXIT_FAILURE;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  memset (cmp.file, 0, sizeof cmp.file);
Packit Service fdd496
  cmp.parent = parent;
Packit Service fdd496
Packit Service fdd496
  /* cmp.file[f].desc markers */
Packit Service fdd496
#define NONEXISTENT (-1) /* nonexistent file */
Packit Service fdd496
#define UNOPENED (-2) /* unopened file (e.g. directory) */
Packit Service fdd496
#define ERRNO_ENCODE(errno) (-3 - (errno)) /* encoded errno value */
Packit Service fdd496
Packit Service fdd496
#define ERRNO_DECODE(desc) (-3 - (desc)) /* inverse of ERRNO_ENCODE */
Packit Service fdd496
Packit Service fdd496
  cmp.file[0].desc = name0 ? UNOPENED : NONEXISTENT;
Packit Service fdd496
  cmp.file[1].desc = name1 ? UNOPENED : NONEXISTENT;
Packit Service fdd496
Packit Service fdd496
  /* Now record the full name of each file, including nonexistent ones.  */
Packit Service fdd496
Packit Service fdd496
  if (!name0)
Packit Service fdd496
    name0 = name1;
Packit Service fdd496
  if (!name1)
Packit Service fdd496
    name1 = name0;
Packit Service fdd496
Packit Service fdd496
  if (!parent)
Packit Service fdd496
    {
Packit Service fdd496
      free0 = NULL;
Packit Service fdd496
      free1 = NULL;
Packit Service fdd496
      cmp.file[0].name = name0;
Packit Service fdd496
      cmp.file[1].name = name1;
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      cmp.file[0].name = free0
Packit Service fdd496
	= file_name_concat (parent->file[0].name, name0, NULL);
Packit Service fdd496
      cmp.file[1].name = free1
Packit Service fdd496
	= file_name_concat (parent->file[1].name, name1, NULL);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  /* Stat the files.  */
Packit Service fdd496
Packit Service fdd496
  for (f = 0; f < 2; f++)
Packit Service fdd496
    {
Packit Service fdd496
      if (cmp.file[f].desc != NONEXISTENT)
Packit Service fdd496
	{
Packit Service fdd496
	  if (f && file_name_cmp (cmp.file[f].name, cmp.file[0].name) == 0)
Packit Service fdd496
	    {
Packit Service fdd496
	      cmp.file[f].desc = cmp.file[0].desc;
Packit Service fdd496
	      cmp.file[f].stat = cmp.file[0].stat;
Packit Service fdd496
	    }
Packit Service fdd496
	  else if (STREQ (cmp.file[f].name, "-"))
Packit Service fdd496
	    {
Packit Service fdd496
	      cmp.file[f].desc = STDIN_FILENO;
Packit Service fdd496
	      if (binary && ! isatty (STDIN_FILENO))
Packit Service fdd496
		set_binary_mode (STDIN_FILENO, O_BINARY);
Packit Service fdd496
	      if (fstat (STDIN_FILENO, &cmp.file[f].stat) != 0)
Packit Service fdd496
		cmp.file[f].desc = ERRNO_ENCODE (errno);
Packit Service fdd496
	      else
Packit Service fdd496
		{
Packit Service fdd496
		  if (S_ISREG (cmp.file[f].stat.st_mode))
Packit Service fdd496
		    {
Packit Service fdd496
		      off_t pos = lseek (STDIN_FILENO, 0, SEEK_CUR);
Packit Service fdd496
		      if (pos < 0)
Packit Service fdd496
			cmp.file[f].desc = ERRNO_ENCODE (errno);
Packit Service fdd496
		      else
Packit Service fdd496
			cmp.file[f].stat.st_size =
Packit Service fdd496
			  MAX (0, cmp.file[f].stat.st_size - pos);
Packit Service fdd496
		    }
Packit Service fdd496
Packit Service fdd496
		  /* POSIX 1003.1-2001 requires current time for
Packit Service fdd496
		     stdin.  */
Packit Service fdd496
		  set_mtime_to_now (&cmp.file[f].stat);
Packit Service fdd496
		}
Packit Service fdd496
	    }
Packit Service fdd496
	  else if ((no_dereference_symlinks
Packit Service fdd496
		    ? lstat (cmp.file[f].name, &cmp.file[f].stat)
Packit Service fdd496
		    : stat (cmp.file[f].name, &cmp.file[f].stat))
Packit Service fdd496
		   != 0)
Packit Service fdd496
	    cmp.file[f].desc = ERRNO_ENCODE (errno);
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  /* Mark files as nonexistent as needed for -N and -P, if they are
Packit Service fdd496
     inaccessible empty regular files (the kind of files that 'patch'
Packit Service fdd496
     creates to indicate nonexistent backups), or if they are
Packit Service fdd496
     top-level files that do not exist but their counterparts do
Packit Service fdd496
     exist.  */
Packit Service fdd496
  for (f = 0; f < 2; f++)
Packit Service fdd496
    if ((new_file || (f == 0 && unidirectional_new_file))
Packit Service fdd496
	&& (cmp.file[f].desc == UNOPENED
Packit Service fdd496
	    ? (S_ISREG (cmp.file[f].stat.st_mode)
Packit Service fdd496
	       && ! (cmp.file[f].stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO))
Packit Service fdd496
	       && cmp.file[f].stat.st_size == 0)
Packit Service fdd496
	    : ((cmp.file[f].desc == ERRNO_ENCODE (ENOENT)
Packit Service fdd496
		|| cmp.file[f].desc == ERRNO_ENCODE (EBADF))
Packit Service fdd496
	       && ! parent
Packit Service fdd496
	       && (cmp.file[1 - f].desc == UNOPENED
Packit Service fdd496
		   || cmp.file[1 - f].desc == STDIN_FILENO))))
Packit Service fdd496
      cmp.file[f].desc = NONEXISTENT;
Packit Service fdd496
Packit Service fdd496
  for (f = 0; f < 2; f++)
Packit Service fdd496
    if (cmp.file[f].desc == NONEXISTENT)
Packit Service fdd496
      {
Packit Service fdd496
	memset (&cmp.file[f].stat, 0, sizeof cmp.file[f].stat);
Packit Service fdd496
	cmp.file[f].stat.st_mode = cmp.file[1 - f].stat.st_mode;
Packit Service fdd496
      }
Packit Service fdd496
Packit Service fdd496
  for (f = 0; f < 2; f++)
Packit Service fdd496
    {
Packit Service fdd496
      int e = ERRNO_DECODE (cmp.file[f].desc);
Packit Service fdd496
      if (0 <= e)
Packit Service fdd496
	{
Packit Service fdd496
	  errno = e;
Packit Service fdd496
	  perror_with_name (cmp.file[f].name);
Packit Service fdd496
	  status = EXIT_TROUBLE;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  if (status == EXIT_SUCCESS && ! parent && DIR_P (0) != DIR_P (1))
Packit Service fdd496
    {
Packit Service fdd496
      /* If one is a directory, and it was specified in the command line,
Packit Service fdd496
	 use the file in that dir with the other file's basename.  */
Packit Service fdd496
Packit Service fdd496
      int fnm_arg = DIR_P (0);
Packit Service fdd496
      int dir_arg = 1 - fnm_arg;
Packit Service fdd496
      char const *fnm = cmp.file[fnm_arg].name;
Packit Service fdd496
      char const *dir = cmp.file[dir_arg].name;
Packit Service fdd496
      char const *filename = cmp.file[dir_arg].name = free0
Packit Service fdd496
	= find_dir_file_pathname (dir, last_component (fnm));
Packit Service fdd496
Packit Service fdd496
      if (STREQ (fnm, "-"))
Packit Service fdd496
	fatal ("cannot compare '-' to a directory");
Packit Service fdd496
Packit Service fdd496
      if ((no_dereference_symlinks
Packit Service fdd496
	   ? lstat (filename, &cmp.file[dir_arg].stat)
Packit Service fdd496
	   : stat (filename, &cmp.file[dir_arg].stat))
Packit Service fdd496
	  != 0)
Packit Service fdd496
	{
Packit Service fdd496
	  perror_with_name (filename);
Packit Service fdd496
	  status = EXIT_TROUBLE;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  if (status != EXIT_SUCCESS)
Packit Service fdd496
    {
Packit Service fdd496
      /* One of the files should exist but does not.  */
Packit Service fdd496
    }
Packit Service fdd496
  else if (cmp.file[0].desc == NONEXISTENT
Packit Service fdd496
	   && cmp.file[1].desc == NONEXISTENT)
Packit Service fdd496
    {
Packit Service fdd496
      /* Neither file "exists", so there's nothing to compare.  */
Packit Service fdd496
    }
Packit Service fdd496
  else if ((same_files
Packit Service fdd496
	    = (cmp.file[0].desc != NONEXISTENT
Packit Service fdd496
	       && cmp.file[1].desc != NONEXISTENT
Packit Service fdd496
	       && 0 < same_file (&cmp.file[0].stat, &cmp.file[1].stat)
Packit Service fdd496
	       && same_file_attributes (&cmp.file[0].stat,
Packit Service fdd496
					&cmp.file[1].stat)))
Packit Service fdd496
	   && no_diff_means_no_output)
Packit Service fdd496
    {
Packit Service fdd496
      /* The two named files are actually the same physical file.
Packit Service fdd496
	 We know they are identical without actually reading them.  */
Packit Service fdd496
    }
Packit Service fdd496
  else if (DIR_P (0) & DIR_P (1))
Packit Service fdd496
    {
Packit Service fdd496
      if (output_style == OUTPUT_IFDEF)
Packit Service fdd496
	fatal ("-D option not supported with directories");
Packit Service fdd496
Packit Service fdd496
      /* If both are directories, compare the files in them.  */
Packit Service fdd496
Packit Service fdd496
      if (parent && !recursive)
Packit Service fdd496
	{
Packit Service fdd496
	  /* But don't compare dir contents one level down
Packit Service fdd496
	     unless -r was specified.
Packit Service fdd496
	     See POSIX 1003.1-2001 for this format.  */
Packit Service fdd496
	  message ("Common subdirectories: %s and %s\n",
Packit Service fdd496
		   cmp.file[0].name, cmp.file[1].name);
Packit Service fdd496
	}
Packit Service fdd496
      else
Packit Service fdd496
	status = diff_dirs (&cmp, compare_files);
Packit Service fdd496
    }
Packit Service fdd496
  else if ((DIR_P (0) | DIR_P (1))
Packit Service fdd496
	   || (parent
Packit Service fdd496
	       && !((S_ISREG (cmp.file[0].stat.st_mode)
Packit Service fdd496
		     || S_ISLNK (cmp.file[0].stat.st_mode))
Packit Service fdd496
		    && (S_ISREG (cmp.file[1].stat.st_mode)
Packit Service fdd496
			|| S_ISLNK  (cmp.file[1].stat.st_mode)))))
Packit Service fdd496
    {
Packit Service fdd496
      if (cmp.file[0].desc == NONEXISTENT || cmp.file[1].desc == NONEXISTENT)
Packit Service fdd496
	{
Packit Service fdd496
	  /* We have a subdirectory that exists only in one directory.  */
Packit Service fdd496
Packit Service fdd496
	  if ((DIR_P (0) | DIR_P (1))
Packit Service fdd496
	      && recursive
Packit Service fdd496
	      && (new_file
Packit Service fdd496
		  || (unidirectional_new_file
Packit Service fdd496
		      && cmp.file[0].desc == NONEXISTENT)))
Packit Service fdd496
	    status = diff_dirs (&cmp, compare_files);
Packit Service fdd496
	  else
Packit Service fdd496
	    {
Packit Service fdd496
	      char const *dir;
Packit Service fdd496
Packit Service fdd496
	      /* PARENT must be non-NULL here.  */
Packit Service fdd496
	      assert (parent);
Packit Service fdd496
	      dir = parent->file[cmp.file[0].desc == NONEXISTENT].name;
Packit Service fdd496
Packit Service fdd496
	      /* See POSIX 1003.1-2001 for this format.  */
Packit Service fdd496
	      message ("Only in %s: %s\n", dir, name0);
Packit Service fdd496
Packit Service fdd496
	      status = EXIT_FAILURE;
Packit Service fdd496
	    }
Packit Service fdd496
	}
Packit Service fdd496
      else
Packit Service fdd496
	{
Packit Service fdd496
	  /* We have two files that are not to be compared.  */
Packit Service fdd496
Packit Service fdd496
	  /* See POSIX 1003.1-2001 for this format.  */
Packit Service fdd496
	  message5 ("File %s is a %s while file %s is a %s\n",
Packit Service fdd496
		    file_label[0] ? file_label[0] : cmp.file[0].name,
Packit Service fdd496
		    file_type (&cmp.file[0].stat),
Packit Service fdd496
		    file_label[1] ? file_label[1] : cmp.file[1].name,
Packit Service fdd496
		    file_type (&cmp.file[1].stat));
Packit Service fdd496
Packit Service fdd496
	  /* This is a difference.  */
Packit Service fdd496
	  status = EXIT_FAILURE;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
  else if (S_ISLNK (cmp.file[0].stat.st_mode)
Packit Service fdd496
	   || S_ISLNK (cmp.file[1].stat.st_mode))
Packit Service fdd496
    {
Packit Service fdd496
      /* We get here only if we use lstat(), not stat().  */
Packit Service fdd496
      assert (no_dereference_symlinks);
Packit Service fdd496
Packit Service fdd496
      if (S_ISLNK (cmp.file[0].stat.st_mode)
Packit Service fdd496
	  && S_ISLNK (cmp.file[1].stat.st_mode))
Packit Service fdd496
	{
Packit Service fdd496
	  /* Compare the values of the symbolic links.  */
Packit Service fdd496
	  char *link_value[2] = { NULL, NULL };
Packit Service fdd496
Packit Service fdd496
	  for (f = 0; f < 2; f++)
Packit Service fdd496
	    {
Packit Service fdd496
	      link_value[f] = xreadlink (cmp.file[f].name);
Packit Service fdd496
	      if (link_value[f] == NULL)
Packit Service fdd496
		{
Packit Service fdd496
		  perror_with_name (cmp.file[f].name);
Packit Service fdd496
		  status = EXIT_TROUBLE;
Packit Service fdd496
		  break;
Packit Service fdd496
		}
Packit Service fdd496
	    }
Packit Service fdd496
	  if (status == EXIT_SUCCESS)
Packit Service fdd496
	    {
Packit Service fdd496
	      if ( ! STREQ (link_value[0], link_value[1]))
Packit Service fdd496
		{
Packit Service fdd496
		  message ("Symbolic links %s and %s differ\n",
Packit Service fdd496
			   cmp.file[0].name, cmp.file[1].name);
Packit Service fdd496
		  /* This is a difference.  */
Packit Service fdd496
		  status = EXIT_FAILURE;
Packit Service fdd496
		}
Packit Service fdd496
	    }
Packit Service fdd496
	  for (f = 0; f < 2; f++)
Packit Service fdd496
	    free (link_value[f]);
Packit Service fdd496
	}
Packit Service fdd496
      else
Packit Service fdd496
	{
Packit Service fdd496
	  /* We have two files that are not to be compared, because
Packit Service fdd496
	     one of them is a symbolic link and the other one is not.  */
Packit Service fdd496
Packit Service fdd496
	  message5 ("File %s is a %s while file %s is a %s\n",
Packit Service fdd496
		    file_label[0] ? file_label[0] : cmp.file[0].name,
Packit Service fdd496
		    file_type (&cmp.file[0].stat),
Packit Service fdd496
		    file_label[1] ? file_label[1] : cmp.file[1].name,
Packit Service fdd496
		    file_type (&cmp.file[1].stat));
Packit Service fdd496
Packit Service fdd496
	  /* This is a difference.  */
Packit Service fdd496
	  status = EXIT_FAILURE;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
  else if (files_can_be_treated_as_binary
Packit Service fdd496
	   && S_ISREG (cmp.file[0].stat.st_mode)
Packit Service fdd496
	   && S_ISREG (cmp.file[1].stat.st_mode)
Packit Service fdd496
	   && cmp.file[0].stat.st_size != cmp.file[1].stat.st_size
Packit Service fdd496
	   && 0 < cmp.file[0].stat.st_size
Packit Service fdd496
	   && 0 < cmp.file[1].stat.st_size)
Packit Service fdd496
    {
Packit Service fdd496
      message ("Files %s and %s differ\n",
Packit Service fdd496
	       file_label[0] ? file_label[0] : cmp.file[0].name,
Packit Service fdd496
	       file_label[1] ? file_label[1] : cmp.file[1].name);
Packit Service fdd496
      status = EXIT_FAILURE;
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      /* Both exist and neither is a directory.  */
Packit Service fdd496
Packit Service fdd496
      /* Open the files and record their descriptors.  */
Packit Service fdd496
Packit Service fdd496
      int oflags = O_RDONLY | (binary ? O_BINARY : 0);
Packit Service fdd496
Packit Service fdd496
      if (cmp.file[0].desc == UNOPENED)
Packit Service fdd496
	if ((cmp.file[0].desc = open (cmp.file[0].name, oflags, 0)) < 0)
Packit Service fdd496
	  {
Packit Service fdd496
	    perror_with_name (cmp.file[0].name);
Packit Service fdd496
	    status = EXIT_TROUBLE;
Packit Service fdd496
	  }
Packit Service fdd496
      if (cmp.file[1].desc == UNOPENED)
Packit Service fdd496
	{
Packit Service fdd496
	  if (same_files)
Packit Service fdd496
	    cmp.file[1].desc = cmp.file[0].desc;
Packit Service fdd496
	  else if ((cmp.file[1].desc = open (cmp.file[1].name, oflags, 0)) < 0)
Packit Service fdd496
	    {
Packit Service fdd496
	      perror_with_name (cmp.file[1].name);
Packit Service fdd496
	      status = EXIT_TROUBLE;
Packit Service fdd496
	    }
Packit Service fdd496
	}
Packit Service fdd496
Packit Service fdd496
      /* Compare the files, if no error was found.  */
Packit Service fdd496
Packit Service fdd496
      if (status == EXIT_SUCCESS)
Packit Service fdd496
	status = diff_2_files (&cmp);
Packit Service fdd496
Packit Service fdd496
      /* Close the file descriptors.  */
Packit Service fdd496
Packit Service fdd496
      if (0 <= cmp.file[0].desc && close (cmp.file[0].desc) != 0)
Packit Service fdd496
	{
Packit Service fdd496
	  perror_with_name (cmp.file[0].name);
Packit Service fdd496
	  status = EXIT_TROUBLE;
Packit Service fdd496
	}
Packit Service fdd496
      if (0 <= cmp.file[1].desc && cmp.file[0].desc != cmp.file[1].desc
Packit Service fdd496
	  && close (cmp.file[1].desc) != 0)
Packit Service fdd496
	{
Packit Service fdd496
	  perror_with_name (cmp.file[1].name);
Packit Service fdd496
	  status = EXIT_TROUBLE;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  /* Now the comparison has been done, if no error prevented it,
Packit Service fdd496
     and STATUS is the value this function will return.  */
Packit Service fdd496
Packit Service fdd496
  if (status == EXIT_SUCCESS)
Packit Service fdd496
    {
Packit Service fdd496
      if (report_identical_files && !DIR_P (0))
Packit Service fdd496
	message ("Files %s and %s are identical\n",
Packit Service fdd496
		 file_label[0] ? file_label[0] : cmp.file[0].name,
Packit Service fdd496
		 file_label[1] ? file_label[1] : cmp.file[1].name);
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      /* Flush stdout so that the user sees differences immediately.
Packit Service fdd496
	 This can hurt performance, unfortunately.  */
Packit Service fdd496
      if (fflush (stdout) != 0)
Packit Service fdd496
	pfatal_with_name (_("standard output"));
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  free (free0);
Packit Service fdd496
  free (free1);
Packit Service fdd496
Packit Service fdd496
  return status;
Packit Service fdd496
}