Blame src/sdiff.c

Packit Service fdd496
/* sdiff - side-by-side merge of file differences
Packit Service fdd496
Packit Service fdd496
   Copyright (C) 1992-1996, 1998, 2001-2002, 2004, 2006-2007, 2009-2013,
Packit Service fdd496
   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
#include "system.h"
Packit Service fdd496
#include "paths.h"
Packit Service fdd496
Packit Service fdd496
#include <stdio.h>
Packit Service fdd496
#include <unlocked-io.h>
Packit Service fdd496
Packit Service fdd496
#include <c-stack.h>
Packit Service fdd496
#include <dirname.h>
Packit Service fdd496
#include "die.h"
Packit Service fdd496
#include <error.h>
Packit Service fdd496
#include <exitfail.h>
Packit Service fdd496
#include <file-type.h>
Packit Service fdd496
#include <getopt.h>
Packit Service fdd496
#include <progname.h>
Packit Service fdd496
#include <system-quote.h>
Packit Service fdd496
#include <version-etc.h>
Packit Service fdd496
#include <xalloc.h>
Packit Service fdd496
Packit Service fdd496
/* The official name of this program (e.g., no 'g' prefix).  */
Packit Service fdd496
#define PROGRAM_NAME "sdiff"
Packit Service fdd496
Packit Service fdd496
#define AUTHORS \
Packit Service fdd496
  proper_name ("Thomas Lord")
Packit Service fdd496
Packit Service fdd496
/* Size of chunks read from files which must be parsed into lines.  */
Packit Service fdd496
#define SDIFF_BUFSIZE ((size_t) 65536)
Packit Service fdd496
Packit Service fdd496
static char const *editor_program = DEFAULT_EDITOR_PROGRAM;
Packit Service fdd496
static char const **diffargv;
Packit Service fdd496
Packit Service fdd496
static char * volatile tmpname;
Packit Service fdd496
static FILE *tmp;
Packit Service fdd496
Packit Service fdd496
#if HAVE_WORKING_FORK
Packit Service fdd496
static pid_t volatile diffpid;
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
struct line_filter;
Packit Service fdd496
Packit Service fdd496
static void catchsig (int);
Packit Service fdd496
static bool edit (struct line_filter *, char const *, lin, lin, struct line_filter *, char const *, lin, lin, FILE *);
Packit Service fdd496
static bool interact (struct line_filter *, struct line_filter *, char const *, struct line_filter *, char const *, FILE *);
Packit Service fdd496
static void checksigs (void);
Packit Service fdd496
static void diffarg (char const *);
Packit Service fdd496
static void fatal (char const *) __attribute__((noreturn));
Packit Service fdd496
static void perror_fatal (char const *) __attribute__((noreturn));
Packit Service fdd496
static void trapsigs (void);
Packit Service fdd496
static void untrapsig (int);
Packit Service fdd496
Packit Service fdd496
static int const sigs[] = {
Packit Service fdd496
#ifdef SIGHUP
Packit Service fdd496
       SIGHUP,
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGQUIT
Packit Service fdd496
       SIGQUIT,
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGTERM
Packit Service fdd496
       SIGTERM,
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGXCPU
Packit Service fdd496
       SIGXCPU,
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGXFSZ
Packit Service fdd496
       SIGXFSZ,
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGPIPE
Packit Service fdd496
       SIGPIPE,
Packit Service fdd496
#endif
Packit Service fdd496
       SIGINT
Packit Service fdd496
};
Packit Service fdd496
enum
Packit Service fdd496
  {
Packit Service fdd496
    NUM_SIGS = sizeof sigs / sizeof *sigs,
Packit Service fdd496
    handler_index_of_SIGINT = NUM_SIGS - 1
Packit Service fdd496
  };
Packit Service fdd496
Packit Service fdd496
#if HAVE_SIGACTION
Packit Service fdd496
  /* Prefer 'sigaction' if available, since 'signal' can lose signals.  */
Packit Service fdd496
  static struct sigaction initial_action[NUM_SIGS];
Packit Service fdd496
# define initial_handler(i) (initial_action[i].sa_handler)
Packit Service fdd496
  static void signal_handler (int, void (*) (int));
Packit Service fdd496
#else
Packit Service fdd496
  static void (*initial_action[NUM_SIGS]) ();
Packit Service fdd496
# define initial_handler(i) (initial_action[i])
Packit Service fdd496
# define signal_handler(sig, handler) signal (sig, handler)
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
static bool diraccess (char const *);
Packit Service fdd496
static int temporary_file (void);
Packit Service fdd496
Packit Service fdd496
/* Options: */
Packit Service fdd496
Packit Service fdd496
/* Name of output file if -o specified.  */
Packit Service fdd496
static char const *output;
Packit Service fdd496
Packit Service fdd496
/* Do not print common lines.  */
Packit Service fdd496
static bool suppress_common_lines;
Packit Service fdd496
Packit Service fdd496
/* Value for the long option that does not have single-letter equivalents.  */
Packit Service fdd496
enum
Packit Service fdd496
{
Packit Service fdd496
  DIFF_PROGRAM_OPTION = CHAR_MAX + 1,
Packit Service fdd496
  HELP_OPTION,
Packit Service fdd496
  STRIP_TRAILING_CR_OPTION,
Packit Service fdd496
  TABSIZE_OPTION
Packit Service fdd496
};
Packit Service fdd496
Packit Service fdd496
static struct option const longopts[] =
Packit Service fdd496
{
Packit Service fdd496
  {"diff-program", 1, 0, DIFF_PROGRAM_OPTION},
Packit Service fdd496
  {"expand-tabs", 0, 0, 't'},
Packit Service fdd496
  {"help", 0, 0, HELP_OPTION},
Packit Service fdd496
  {"ignore-all-space", 0, 0, 'W'}, /* swap W and w for historical reasons */
Packit Service fdd496
  {"ignore-blank-lines", 0, 0, 'B'},
Packit Service fdd496
  {"ignore-case", 0, 0, 'i'},
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
  {"left-column", 0, 0, 'l'},
Packit Service fdd496
  {"minimal", 0, 0, 'd'},
Packit Service fdd496
  {"output", 1, 0, 'o'},
Packit Service fdd496
  {"speed-large-files", 0, 0, 'H'},
Packit Service fdd496
  {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},
Packit Service fdd496
  {"suppress-common-lines", 0, 0, 's'},
Packit Service fdd496
  {"tabsize", 1, 0, TABSIZE_OPTION},
Packit Service fdd496
  {"text", 0, 0, 'a'},
Packit Service fdd496
  {"version", 0, 0, 'v'},
Packit Service fdd496
  {"width", 1, 0, 'w'},
Packit Service fdd496
  {0, 0, 0, 0}
Packit Service fdd496
};
Packit Service fdd496
Packit Service fdd496
static void try_help (char const *, char const *) __attribute__((noreturn));
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
    perror_fatal (_("standard output"));
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static char const * const option_help_msgid[] = {
Packit Service fdd496
  N_("-o, --output=FILE            operate interactively, sending output to FILE"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("-i, --ignore-case            consider upper- and lower-case to be the same"),
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 whose lines are all blank"),
Packit Service fdd496
  N_("-I, --ignore-matching-lines=RE  ignore changes all whose lines match RE"),
Packit Service fdd496
  N_("    --strip-trailing-cr      strip trailing carriage return on input"),
Packit Service fdd496
  N_("-a, --text                   treat all files as text"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("-w, --width=NUM              output at most NUM (default 130) print columns"),
Packit Service fdd496
  N_("-l, --left-column            output only the left column of common lines"),
Packit Service fdd496
  N_("-s, --suppress-common-lines  do not output common lines"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("-t, --expand-tabs            expand tabs to spaces in output"),
Packit Service fdd496
  N_("    --tabsize=NUM            tab stops at every NUM (default 8) print columns"),
Packit Service fdd496
  "",
Packit Service fdd496
  N_("-d, --minimal                try hard to find a smaller set of changes"),
Packit Service fdd496
  N_("-H, --speed-large-files      assume large files, many scattered small changes"),
Packit Service fdd496
  N_("    --diff-program=PROGRAM   use PROGRAM to compare files"),
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
  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]... FILE1 FILE2\n"), program_name);
Packit Service fdd496
  printf ("%s\n\n",
Packit Service fdd496
          _("Side-by-side merge of differences between FILE1 and FILE2."));
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
  for (p = option_help_msgid;  *p;  p++)
Packit Service fdd496
    if (**p)
Packit Service fdd496
      printf ("  %s\n", _(*p));
Packit Service fdd496
    else
Packit Service fdd496
      putchar ('\n');
Packit Service fdd496
  printf ("\n%s\n%s\n",
Packit Service fdd496
	  _("If a FILE is '-', read standard input."),
Packit Service fdd496
	  _("Exit status is 0 if inputs are the same, 1 if different, 2 if trouble."));
Packit Service fdd496
  emit_bug_reporting_address ();
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Clean up after a signal or other failure.  This function is
Packit Service fdd496
   async-signal-safe.  */
Packit Service fdd496
static void
Packit Service fdd496
cleanup (int signo __attribute__((unused)))
Packit Service fdd496
{
Packit Service fdd496
#if HAVE_WORKING_FORK
Packit Service fdd496
  if (0 < diffpid)
Packit Service fdd496
    kill (diffpid, SIGPIPE);
Packit Service fdd496
#endif
Packit Service fdd496
  if (tmpname)
Packit Service fdd496
    unlink (tmpname);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void exiterr (void) __attribute__((noreturn));
Packit Service fdd496
static void
Packit Service fdd496
exiterr (void)
Packit Service fdd496
{
Packit Service fdd496
  cleanup (0);
Packit Service fdd496
  untrapsig (0);
Packit Service fdd496
  checksigs ();
Packit Service fdd496
  exit (EXIT_TROUBLE);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
fatal (char const *msgid)
Packit Service fdd496
{
Packit Service fdd496
  error (0, 0, "%s", _(msgid));
Packit Service fdd496
  exiterr ();
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
perror_fatal (char const *msg)
Packit Service fdd496
{
Packit Service fdd496
  int e = errno;
Packit Service fdd496
  checksigs ();
Packit Service fdd496
  error (0, e, "%s", msg);
Packit Service fdd496
  exiterr ();
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
check_child_status (int werrno, int wstatus, int max_ok_status,
Packit Service fdd496
		    char const *subsidiary_program)
Packit Service fdd496
{
Packit Service fdd496
  int status = (! werrno && WIFEXITED (wstatus)
Packit Service fdd496
		? WEXITSTATUS (wstatus)
Packit Service fdd496
		: INT_MAX);
Packit Service fdd496
Packit Service fdd496
  if (max_ok_status < status)
Packit Service fdd496
    {
Packit Service fdd496
      error (0, werrno,
Packit Service fdd496
	     _(status == 126
Packit Service fdd496
	       ? "subsidiary program '%s' could not be invoked"
Packit Service fdd496
	       : status == 127
Packit Service fdd496
	       ? "subsidiary program '%s' not found"
Packit Service fdd496
	       : status == INT_MAX
Packit Service fdd496
	       ? "subsidiary program '%s' failed"
Packit Service fdd496
	       : "subsidiary program '%s' failed (exit status %d)"),
Packit Service fdd496
	     subsidiary_program, status);
Packit Service fdd496
      exiterr ();
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static FILE *
Packit Service fdd496
ck_fopen (char const *fname, char const *type)
Packit Service fdd496
{
Packit Service fdd496
  FILE *r = fopen (fname, type);
Packit Service fdd496
  if (! r)
Packit Service fdd496
    perror_fatal (fname);
Packit Service fdd496
  return r;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
ck_fclose (FILE *f)
Packit Service fdd496
{
Packit Service fdd496
  if (fclose (f))
Packit Service fdd496
    perror_fatal ("fclose");
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static size_t
Packit Service fdd496
ck_fread (char *buf, size_t size, FILE *f)
Packit Service fdd496
{
Packit Service fdd496
  size_t r = fread (buf, sizeof (char), size, f);
Packit Service fdd496
  if (r == 0 && ferror (f))
Packit Service fdd496
    perror_fatal (_("read failed"));
Packit Service fdd496
  return r;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
ck_fwrite (char const *buf, size_t size, FILE *f)
Packit Service fdd496
{
Packit Service fdd496
  if (fwrite (buf, sizeof (char), size, f) != size)
Packit Service fdd496
    perror_fatal (_("write failed"));
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
ck_fflush (FILE *f)
Packit Service fdd496
{
Packit Service fdd496
  if (fflush (f) != 0)
Packit Service fdd496
    perror_fatal (_("write failed"));
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static char const *
Packit Service fdd496
expand_name (char *name, bool is_dir, char const *other_name)
Packit Service fdd496
{
Packit Service fdd496
  if (STREQ (name, "-"))
Packit Service fdd496
    fatal ("cannot interactively merge standard input");
Packit Service fdd496
  if (! is_dir)
Packit Service fdd496
    return name;
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      /* Yield NAME/BASE, where BASE is OTHER_NAME's basename.  */
Packit Service fdd496
      char const *base = last_component (other_name);
Packit Service fdd496
      size_t namelen = strlen (name), baselen = base_len (base);
Packit Service fdd496
      bool insert_slash = *last_component (name) && name[namelen - 1] != '/';
Packit Service fdd496
      char *r = xmalloc (namelen + insert_slash + baselen + 1);
Packit Service fdd496
      memcpy (r, name, namelen);
Packit Service fdd496
      r[namelen] = '/';
Packit Service fdd496
      memcpy (r + namelen + insert_slash, base, baselen);
Packit Service fdd496
      r[namelen + insert_slash + baselen] = '\0';
Packit Service fdd496
      return r;
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
struct line_filter {
Packit Service fdd496
  FILE *infile;
Packit Service fdd496
  char *bufpos;
Packit Service fdd496
  char *buffer;
Packit Service fdd496
  char *buflim;
Packit Service fdd496
};
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
lf_init (struct line_filter *lf, FILE *infile)
Packit Service fdd496
{
Packit Service fdd496
  lf->infile = infile;
Packit Service fdd496
  lf->bufpos = lf->buffer = lf->buflim = xmalloc (SDIFF_BUFSIZE + 1);
Packit Service fdd496
  lf->buflim[0] = '\n';
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Fill an exhausted line_filter buffer from its INFILE */
Packit Service fdd496
static size_t
Packit Service fdd496
lf_refill (struct line_filter *lf)
Packit Service fdd496
{
Packit Service fdd496
  size_t s = ck_fread (lf->buffer, SDIFF_BUFSIZE, lf->infile);
Packit Service fdd496
  lf->bufpos = lf->buffer;
Packit Service fdd496
  lf->buflim = lf->buffer + s;
Packit Service fdd496
  lf->buflim[0] = '\n';
Packit Service fdd496
  checksigs ();
Packit Service fdd496
  return s;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Advance LINES on LF's infile, copying lines to OUTFILE */
Packit Service fdd496
static void
Packit Service fdd496
lf_copy (struct line_filter *lf, lin lines, FILE *outfile)
Packit Service fdd496
{
Packit Service fdd496
  char *start = lf->bufpos;
Packit Service fdd496
Packit Service fdd496
  while (lines)
Packit Service fdd496
    {
Packit Service fdd496
      lf->bufpos = rawmemchr (lf->bufpos, '\n');
Packit Service fdd496
      if (lf->bufpos == lf->buflim)
Packit Service fdd496
	{
Packit Service fdd496
	  ck_fwrite (start, lf->buflim - start, outfile);
Packit Service fdd496
	  if (! lf_refill (lf))
Packit Service fdd496
	    return;
Packit Service fdd496
	  start = lf->bufpos;
Packit Service fdd496
	}
Packit Service fdd496
      else
Packit Service fdd496
	{
Packit Service fdd496
	  --lines;
Packit Service fdd496
	  ++lf->bufpos;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  ck_fwrite (start, lf->bufpos - start, outfile);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Advance LINES on LF's infile without doing output */
Packit Service fdd496
static void
Packit Service fdd496
lf_skip (struct line_filter *lf, lin lines)
Packit Service fdd496
{
Packit Service fdd496
  while (lines)
Packit Service fdd496
    {
Packit Service fdd496
      lf->bufpos = rawmemchr (lf->bufpos, '\n');
Packit Service fdd496
      if (lf->bufpos == lf->buflim)
Packit Service fdd496
	{
Packit Service fdd496
	  if (! lf_refill (lf))
Packit Service fdd496
	    break;
Packit Service fdd496
	}
Packit Service fdd496
      else
Packit Service fdd496
	{
Packit Service fdd496
	  --lines;
Packit Service fdd496
	  ++lf->bufpos;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Snarf a line into a buffer.  Return EOF if EOF, 0 if error, 1 if OK.  */
Packit Service fdd496
static int
Packit Service fdd496
lf_snarf (struct line_filter *lf, char *buffer, size_t bufsize)
Packit Service fdd496
{
Packit Service fdd496
  for (;;)
Packit Service fdd496
    {
Packit Service fdd496
      char *start = lf->bufpos;
Packit Service fdd496
      char *next = rawmemchr (start, '\n');
Packit Service fdd496
      size_t s = next - start;
Packit Service fdd496
      if (bufsize <= s)
Packit Service fdd496
	return 0;
Packit Service fdd496
      memcpy (buffer, start, s);
Packit Service fdd496
      if (next < lf->buflim)
Packit Service fdd496
	{
Packit Service fdd496
	  buffer[s] = 0;
Packit Service fdd496
	  lf->bufpos = next + 1;
Packit Service fdd496
	  return 1;
Packit Service fdd496
	}
Packit Service fdd496
      if (! lf_refill (lf))
Packit Service fdd496
	return s ? 0 : EOF;
Packit Service fdd496
      buffer += s;
Packit Service fdd496
      bufsize -= s;
Packit Service fdd496
    }
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 opt;
Packit Service fdd496
  char const *prog;
Packit Service fdd496
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 (cleanup);
Packit Service fdd496
Packit Service fdd496
  prog = getenv ("EDITOR");
Packit Service fdd496
  if (prog)
Packit Service fdd496
    editor_program = prog;
Packit Service fdd496
Packit Service fdd496
  diffarg (DEFAULT_DIFF_PROGRAM);
Packit Service fdd496
Packit Service fdd496
  /* parse command line args */
Packit Service fdd496
  while ((opt = getopt_long (argc, argv, "abBdEHiI:lo:stvw:WZ", longopts, 0))
Packit Service fdd496
	 != -1)
Packit Service fdd496
    {
Packit Service fdd496
      switch (opt)
Packit Service fdd496
	{
Packit Service fdd496
	case 'a':
Packit Service fdd496
	  diffarg ("-a");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'b':
Packit Service fdd496
	  diffarg ("-b");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'B':
Packit Service fdd496
	  diffarg ("-B");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'd':
Packit Service fdd496
	  diffarg ("-d");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'E':
Packit Service fdd496
	  diffarg ("-E");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'H':
Packit Service fdd496
	  diffarg ("-H");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'i':
Packit Service fdd496
	  diffarg ("-i");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'I':
Packit Service fdd496
	  diffarg ("-I");
Packit Service fdd496
	  diffarg (optarg);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'l':
Packit Service fdd496
	  diffarg ("--left-column");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'o':
Packit Service fdd496
	  output = optarg;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 's':
Packit Service fdd496
	  suppress_common_lines = true;
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 't':
Packit Service fdd496
	  diffarg ("-t");
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
	  diffarg ("-W");
Packit Service fdd496
	  diffarg (optarg);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'W':
Packit Service fdd496
	  diffarg ("-w");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case 'Z':
Packit Service fdd496
	  diffarg ("-Z");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case DIFF_PROGRAM_OPTION:
Packit Service fdd496
	  diffargv[0] = optarg;
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 STRIP_TRAILING_CR_OPTION:
Packit Service fdd496
	  diffarg ("--strip-trailing-cr");
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	case TABSIZE_OPTION:
Packit Service fdd496
	  diffarg ("--tabsize");
Packit Service fdd496
	  diffarg (optarg);
Packit Service fdd496
	  break;
Packit Service fdd496
Packit Service fdd496
	default:
Packit Service fdd496
	  try_help (0, 0);
Packit Service fdd496
	}
Packit Service fdd496
    }
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
  if (! output)
Packit Service fdd496
    {
Packit Service fdd496
      /* easy case: diff does everything for us */
Packit Service fdd496
      if (suppress_common_lines)
Packit Service fdd496
	diffarg ("--suppress-common-lines");
Packit Service fdd496
      diffarg ("-y");
Packit Service fdd496
      diffarg ("--");
Packit Service fdd496
      diffarg (argv[optind]);
Packit Service fdd496
      diffarg (argv[optind + 1]);
Packit Service fdd496
      diffarg (0);
Packit Service fdd496
      execvp (diffargv[0], (char **) diffargv);
Packit Service fdd496
      perror_fatal (diffargv[0]);
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      char const *lname, *rname;
Packit Service fdd496
      FILE *left, *right, *out, *diffout;
Packit Service fdd496
      bool interact_ok;
Packit Service fdd496
      struct line_filter lfilt;
Packit Service fdd496
      struct line_filter rfilt;
Packit Service fdd496
      struct line_filter diff_filt;
Packit Service fdd496
      bool leftdir = diraccess (argv[optind]);
Packit Service fdd496
      bool rightdir = diraccess (argv[optind + 1]);
Packit Service fdd496
Packit Service fdd496
      if (leftdir & rightdir)
Packit Service fdd496
	fatal ("both files to be compared are directories");
Packit Service fdd496
Packit Service fdd496
      lname = expand_name (argv[optind], leftdir, argv[optind + 1]);
Packit Service fdd496
      left = ck_fopen (lname, "r");
Packit Service fdd496
      rname = expand_name (argv[optind + 1], rightdir, argv[optind]);
Packit Service fdd496
      right = ck_fopen (rname, "r");
Packit Service fdd496
      out = ck_fopen (output, "w");
Packit Service fdd496
Packit Service fdd496
      diffarg ("--sdiff-merge-assist");
Packit Service fdd496
      diffarg ("--");
Packit Service fdd496
      diffarg (argv[optind]);
Packit Service fdd496
      diffarg (argv[optind + 1]);
Packit Service fdd496
      diffarg (0);
Packit Service fdd496
Packit Service fdd496
      trapsigs ();
Packit Service fdd496
Packit Service fdd496
#if ! HAVE_WORKING_FORK
Packit Service fdd496
      {
Packit Service fdd496
	char *command = system_quote_argv (SCI_SYSTEM, (char **) diffargv);
Packit Service fdd496
	errno = 0;
Packit Service fdd496
	diffout = popen (command, "r");
Packit Service fdd496
	if (! diffout)
Packit Service fdd496
	  perror_fatal (command);
Packit Service fdd496
	free (command);
Packit Service fdd496
      }
Packit Service fdd496
#else
Packit Service fdd496
      {
Packit Service fdd496
	int diff_fds[2];
Packit Service fdd496
Packit Service fdd496
	if (pipe (diff_fds) != 0)
Packit Service fdd496
	  perror_fatal ("pipe");
Packit Service fdd496
Packit Service fdd496
	diffpid = fork ();
Packit Service fdd496
	if (diffpid < 0)
Packit Service fdd496
	  perror_fatal ("fork");
Packit Service fdd496
	if (! diffpid)
Packit Service fdd496
	  {
Packit Service fdd496
	    /* Alter the child's SIGINT and SIGPIPE handlers;
Packit Service fdd496
	       this may munge the parent.
Packit Service fdd496
	       The child ignores SIGINT in case the user interrupts the editor.
Packit Service fdd496
	       The child does not ignore SIGPIPE, even if the parent does.  */
Packit Service fdd496
	    if (initial_handler (handler_index_of_SIGINT) != SIG_IGN)
Packit Service fdd496
	      signal_handler (SIGINT, SIG_IGN);
Packit Service fdd496
	    signal_handler (SIGPIPE, SIG_DFL);
Packit Service fdd496
	    close (diff_fds[0]);
Packit Service fdd496
	    if (diff_fds[1] != STDOUT_FILENO)
Packit Service fdd496
	      {
Packit Service fdd496
		dup2 (diff_fds[1], STDOUT_FILENO);
Packit Service fdd496
		close (diff_fds[1]);
Packit Service fdd496
	      }
Packit Service fdd496
Packit Service fdd496
	    execvp (diffargv[0], (char **) diffargv);
Packit Service fdd496
	    _exit (errno == ENOENT ? 127 : 126);
Packit Service fdd496
	  }
Packit Service fdd496
Packit Service fdd496
	close (diff_fds[1]);
Packit Service fdd496
	diffout = fdopen (diff_fds[0], "r");
Packit Service fdd496
	if (! diffout)
Packit Service fdd496
	  perror_fatal ("fdopen");
Packit Service fdd496
      }
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
      lf_init (&diff_filt, diffout);
Packit Service fdd496
      lf_init (&lfilt, left);
Packit Service fdd496
      lf_init (&rfilt, right);
Packit Service fdd496
Packit Service fdd496
      interact_ok = interact (&diff_filt, &lfilt, lname, &rfilt, rname, out);
Packit Service fdd496
Packit Service fdd496
      ck_fclose (left);
Packit Service fdd496
      ck_fclose (right);
Packit Service fdd496
      ck_fclose (out);
Packit Service fdd496
Packit Service fdd496
      {
Packit Service fdd496
	int wstatus;
Packit Service fdd496
	int werrno = 0;
Packit Service fdd496
Packit Service fdd496
#if ! HAVE_WORKING_FORK
Packit Service fdd496
	wstatus = pclose (diffout);
Packit Service fdd496
	if (wstatus == -1)
Packit Service fdd496
	  werrno = errno;
Packit Service fdd496
#else
Packit Service fdd496
	ck_fclose (diffout);
Packit Service fdd496
	while (waitpid (diffpid, &wstatus, 0) < 0)
Packit Service fdd496
	  if (errno == EINTR)
Packit Service fdd496
	    checksigs ();
Packit Service fdd496
	  else
Packit Service fdd496
	    perror_fatal ("waitpid");
Packit Service fdd496
	diffpid = 0;
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
	if (tmpname)
Packit Service fdd496
	  {
Packit Service fdd496
	    unlink (tmpname);
Packit Service fdd496
	    tmpname = 0;
Packit Service fdd496
	  }
Packit Service fdd496
Packit Service fdd496
	if (! interact_ok)
Packit Service fdd496
	  exiterr ();
Packit Service fdd496
Packit Service fdd496
	check_child_status (werrno, wstatus, EXIT_FAILURE, diffargv[0]);
Packit Service fdd496
	untrapsig (0);
Packit Service fdd496
	checksigs ();
Packit Service fdd496
	exit (WEXITSTATUS (wstatus));
Packit Service fdd496
      }
Packit Service fdd496
    }
Packit Service fdd496
  return EXIT_SUCCESS;			/* Fool '-Wall'.  */
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
diffarg (char const *a)
Packit Service fdd496
{
Packit Service fdd496
  static size_t diffargs, diffarglim;
Packit Service fdd496
Packit Service fdd496
  if (diffargs == diffarglim)
Packit Service fdd496
    {
Packit Service fdd496
      if (! diffarglim)
Packit Service fdd496
	diffarglim = 16;
Packit Service fdd496
      else if (PTRDIFF_MAX / (2 * sizeof *diffargv) <= diffarglim)
Packit Service fdd496
	xalloc_die ();
Packit Service fdd496
      else
Packit Service fdd496
	diffarglim *= 2;
Packit Service fdd496
      diffargv = xrealloc (diffargv, diffarglim * sizeof *diffargv);
Packit Service fdd496
    }
Packit Service fdd496
  diffargv[diffargs++] = a;
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
/* Signal handling */
Packit Service fdd496
Packit Service fdd496
static bool volatile ignore_SIGINT;
Packit Service fdd496
static int volatile signal_received;
Packit Service fdd496
static bool sigs_trapped;
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
catchsig (int s)
Packit Service fdd496
{
Packit Service fdd496
#if ! HAVE_SIGACTION
Packit Service fdd496
  signal (s, SIG_IGN);
Packit Service fdd496
#endif
Packit Service fdd496
  if (! (s == SIGINT && ignore_SIGINT))
Packit Service fdd496
    signal_received = s;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
#if HAVE_SIGACTION
Packit Service fdd496
static struct sigaction catchaction;
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
signal_handler (int sig, void (*handler) (int))
Packit Service fdd496
{
Packit Service fdd496
  catchaction.sa_handler = handler;
Packit Service fdd496
  sigaction (sig, &catchaction, 0);
Packit Service fdd496
}
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
trapsigs (void)
Packit Service fdd496
{
Packit Service fdd496
  int i;
Packit Service fdd496
Packit Service fdd496
#if HAVE_SIGACTION
Packit Service fdd496
  catchaction.sa_flags = SA_RESTART;
Packit Service fdd496
  sigemptyset (&catchaction.sa_mask);
Packit Service fdd496
  for (i = 0;  i < NUM_SIGS;  i++)
Packit Service fdd496
    sigaddset (&catchaction.sa_mask, sigs[i]);
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
  for (i = 0;  i < NUM_SIGS;  i++)
Packit Service fdd496
    {
Packit Service fdd496
#if HAVE_SIGACTION
Packit Service fdd496
      sigaction (sigs[i], 0, &initial_action[i]);
Packit Service fdd496
#else
Packit Service fdd496
      initial_action[i] = signal (sigs[i], SIG_IGN);
Packit Service fdd496
#endif
Packit Service fdd496
      if (initial_handler (i) != SIG_IGN)
Packit Service fdd496
	signal_handler (sigs[i], catchsig);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
#ifdef SIGCHLD
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
Packit Service fdd496
  sigs_trapped = true;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Untrap signal S, or all trapped signals if S is zero.  */
Packit Service fdd496
static void
Packit Service fdd496
untrapsig (int s)
Packit Service fdd496
{
Packit Service fdd496
  int i;
Packit Service fdd496
Packit Service fdd496
  if (sigs_trapped)
Packit Service fdd496
    for (i = 0;  i < NUM_SIGS;  i++)
Packit Service fdd496
      if ((! s || sigs[i] == s)  &&  initial_handler (i) != SIG_IGN)
Packit Service fdd496
	{
Packit Service fdd496
#if HAVE_SIGACTION
Packit Service fdd496
	  sigaction (sigs[i], &initial_action[i], 0);
Packit Service fdd496
#else
Packit Service fdd496
	  signal (sigs[i], initial_action[i]);
Packit Service fdd496
#endif
Packit Service fdd496
	}
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Exit if a signal has been received.  */
Packit Service fdd496
static void
Packit Service fdd496
checksigs (void)
Packit Service fdd496
{
Packit Service fdd496
  int s = signal_received;
Packit Service fdd496
  if (s)
Packit Service fdd496
    {
Packit Service fdd496
      cleanup (0);
Packit Service fdd496
Packit Service fdd496
      /* Yield an exit status indicating that a signal was received.  */
Packit Service fdd496
      untrapsig (s);
Packit Service fdd496
      kill (getpid (), s);
Packit Service fdd496
Packit Service fdd496
      /* That didn't work, so exit with error status.  */
Packit Service fdd496
      exit (EXIT_TROUBLE);
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
static void
Packit Service fdd496
give_help (void)
Packit Service fdd496
{
Packit Service fdd496
  fprintf (stderr, "%s", _("\
Packit Service fdd496
ed:\tEdit then use both versions, each decorated with a header.\n\
Packit Service fdd496
eb:\tEdit then use both versions.\n\
Packit Service fdd496
el or e1:\tEdit then use the left version.\n\
Packit Service fdd496
er or e2:\tEdit then use the right version.\n\
Packit Service fdd496
e:\tDiscard both versions then edit a new one.\n\
Packit Service fdd496
l or 1:\tUse the left version.\n\
Packit Service fdd496
r or 2:\tUse the right version.\n\
Packit Service fdd496
s:\tSilently include common lines.\n\
Packit Service fdd496
v:\tVerbosely include common lines.\n\
Packit Service fdd496
q:\tQuit.\n\
Packit Service fdd496
"));
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
skip_white (void)
Packit Service fdd496
{
Packit Service fdd496
  int c;
Packit Service fdd496
  for (;;)
Packit Service fdd496
    {
Packit Service fdd496
      c = getchar ();
Packit Service fdd496
      if (! isspace (c) || c == '\n')
Packit Service fdd496
	break;
Packit Service fdd496
      checksigs ();
Packit Service fdd496
    }
Packit Service fdd496
  if (ferror (stdin))
Packit Service fdd496
    perror_fatal (_("read failed"));
Packit Service fdd496
  return c;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
flush_line (void)
Packit Service fdd496
{
Packit Service fdd496
  int c;
Packit Service fdd496
  while ((c = getchar ()) != '\n' && c != EOF)
Packit Service fdd496
    continue;
Packit Service fdd496
  if (ferror (stdin))
Packit Service fdd496
    perror_fatal (_("read failed"));
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* interpret an edit command */
Packit Service fdd496
static bool
Packit Service fdd496
edit (struct line_filter *left, char const *lname, lin lline, lin llen,
Packit Service fdd496
      struct line_filter *right, char const *rname, lin rline, lin rlen,
Packit Service fdd496
      FILE *outfile)
Packit Service fdd496
{
Packit Service fdd496
  for (;;)
Packit Service fdd496
    {
Packit Service fdd496
      int cmd0 IF_LINT (= 0);
Packit Service fdd496
      int cmd1 IF_LINT (= 0);
Packit Service fdd496
      bool gotcmd = false;
Packit Service fdd496
Packit Service fdd496
      while (! gotcmd)
Packit Service fdd496
	{
Packit Service fdd496
	  if (putchar ('%') != '%')
Packit Service fdd496
	    perror_fatal (_("write failed"));
Packit Service fdd496
	  ck_fflush (stdout);
Packit Service fdd496
Packit Service fdd496
	  cmd0 = skip_white ();
Packit Service fdd496
	  switch (cmd0)
Packit Service fdd496
	    {
Packit Service fdd496
	    case '1': case '2': case 'l': case 'r':
Packit Service fdd496
	    case 's': case 'v': case 'q':
Packit Service fdd496
	      if (skip_white () != '\n')
Packit Service fdd496
		{
Packit Service fdd496
		  give_help ();
Packit Service fdd496
		  flush_line ();
Packit Service fdd496
		  continue;
Packit Service fdd496
		}
Packit Service fdd496
	      gotcmd = true;
Packit Service fdd496
	      break;
Packit Service fdd496
Packit Service fdd496
	    case 'e':
Packit Service fdd496
	      cmd1 = skip_white ();
Packit Service fdd496
	      switch (cmd1)
Packit Service fdd496
		{
Packit Service fdd496
		case '1': case '2': case 'b': case 'd': case 'l': case 'r':
Packit Service fdd496
		  if (skip_white () != '\n')
Packit Service fdd496
		    {
Packit Service fdd496
		      give_help ();
Packit Service fdd496
		      flush_line ();
Packit Service fdd496
		      continue;
Packit Service fdd496
		    }
Packit Service fdd496
		  gotcmd = true;
Packit Service fdd496
		  break;
Packit Service fdd496
		case '\n':
Packit Service fdd496
		  gotcmd = true;
Packit Service fdd496
		  break;
Packit Service fdd496
		default:
Packit Service fdd496
		  give_help ();
Packit Service fdd496
		  flush_line ();
Packit Service fdd496
		  continue;
Packit Service fdd496
		}
Packit Service fdd496
	      break;
Packit Service fdd496
Packit Service fdd496
	    case EOF:
Packit Service fdd496
	      if (feof (stdin))
Packit Service fdd496
		{
Packit Service fdd496
		  gotcmd = true;
Packit Service fdd496
		  cmd0 = 'q';
Packit Service fdd496
		  break;
Packit Service fdd496
		}
Packit Service fdd496
	      FALLTHROUGH;
Packit Service fdd496
	    default:
Packit Service fdd496
	      flush_line ();
Packit Service fdd496
	      FALLTHROUGH;
Packit Service fdd496
	    case '\n':
Packit Service fdd496
	      give_help ();
Packit Service fdd496
	      continue;
Packit Service fdd496
	    }
Packit Service fdd496
	}
Packit Service fdd496
Packit Service fdd496
      switch (cmd0)
Packit Service fdd496
	{
Packit Service fdd496
	case '1': case 'l':
Packit Service fdd496
	  lf_copy (left, llen, outfile);
Packit Service fdd496
	  lf_skip (right, rlen);
Packit Service fdd496
	  return true;
Packit Service fdd496
	case '2': case 'r':
Packit Service fdd496
	  lf_copy (right, rlen, outfile);
Packit Service fdd496
	  lf_skip (left, llen);
Packit Service fdd496
	  return true;
Packit Service fdd496
	case 's':
Packit Service fdd496
	  suppress_common_lines = true;
Packit Service fdd496
	  break;
Packit Service fdd496
	case 'v':
Packit Service fdd496
	  suppress_common_lines = false;
Packit Service fdd496
	  break;
Packit Service fdd496
	case 'q':
Packit Service fdd496
	  return false;
Packit Service fdd496
	case 'e':
Packit Service fdd496
	  {
Packit Service fdd496
	    int fd;
Packit Service fdd496
Packit Service fdd496
	    if (tmpname)
Packit Service fdd496
	      tmp = fopen (tmpname, "w");
Packit Service fdd496
	    else
Packit Service fdd496
	      {
Packit Service fdd496
		if ((fd = temporary_file ()) < 0)
Packit Service fdd496
		  perror_fatal ("mkstemp");
Packit Service fdd496
		tmp = fdopen (fd, "w");
Packit Service fdd496
	      }
Packit Service fdd496
Packit Service fdd496
	    if (! tmp)
Packit Service fdd496
	      perror_fatal (tmpname);
Packit Service fdd496
Packit Service fdd496
	    switch (cmd1)
Packit Service fdd496
	      {
Packit Service fdd496
	      case 'd':
Packit Service fdd496
		if (llen)
Packit Service fdd496
		  {
Packit Service fdd496
		    printint l1 = lline;
Packit Service fdd496
		    printint l2 = lline + llen - 1;
Packit Service fdd496
		    if (llen == 1)
Packit Service fdd496
		      fprintf (tmp, "--- %s %"pI"d\n", lname, l1);
Packit Service fdd496
		    else
Packit Service fdd496
		      fprintf (tmp, "--- %s %"pI"d,%"pI"d\n", lname, l1, l2);
Packit Service fdd496
		  }
Packit Service fdd496
		FALLTHROUGH;
Packit Service fdd496
	      case '1': case 'b': case 'l':
Packit Service fdd496
		lf_copy (left, llen, tmp);
Packit Service fdd496
		break;
Packit Service fdd496
Packit Service fdd496
	      default:
Packit Service fdd496
		lf_skip (left, llen);
Packit Service fdd496
		break;
Packit Service fdd496
	      }
Packit Service fdd496
Packit Service fdd496
	    switch (cmd1)
Packit Service fdd496
	      {
Packit Service fdd496
	      case 'd':
Packit Service fdd496
		if (rlen)
Packit Service fdd496
		  {
Packit Service fdd496
		    printint l1 = rline;
Packit Service fdd496
		    printint l2 = rline + rlen - 1;
Packit Service fdd496
		    if (rlen == 1)
Packit Service fdd496
		      fprintf (tmp, "+++ %s %"pI"d\n", rname, l1);
Packit Service fdd496
		    else
Packit Service fdd496
		      fprintf (tmp, "+++ %s %"pI"d,%"pI"d\n", rname, l1, l2);
Packit Service fdd496
		  }
Packit Service fdd496
		FALLTHROUGH;
Packit Service fdd496
	      case '2': case 'b': case 'r':
Packit Service fdd496
		lf_copy (right, rlen, tmp);
Packit Service fdd496
		break;
Packit Service fdd496
Packit Service fdd496
	      default:
Packit Service fdd496
		lf_skip (right, rlen);
Packit Service fdd496
		break;
Packit Service fdd496
	      }
Packit Service fdd496
Packit Service fdd496
	    ck_fclose (tmp);
Packit Service fdd496
Packit Service fdd496
	    {
Packit Service fdd496
	      int wstatus;
Packit Service fdd496
	      int werrno = 0;
Packit Service fdd496
	      char const *argv[3];
Packit Service fdd496
Packit Service fdd496
	      ignore_SIGINT = true;
Packit Service fdd496
	      checksigs ();
Packit Service fdd496
	      argv[0] = editor_program;
Packit Service fdd496
	      argv[1] = tmpname;
Packit Service fdd496
	      argv[2] = 0;
Packit Service fdd496
Packit Service fdd496
	      {
Packit Service fdd496
#if ! HAVE_WORKING_FORK
Packit Service fdd496
		char *command = system_quote_argv (SCI_SYSTEM, (char **) argv);
Packit Service fdd496
		wstatus = system (command);
Packit Service fdd496
		if (wstatus == -1)
Packit Service fdd496
		  werrno = errno;
Packit Service fdd496
		free (command);
Packit Service fdd496
#else
Packit Service fdd496
		pid_t pid;
Packit Service fdd496
Packit Service fdd496
		pid = fork ();
Packit Service fdd496
		if (pid == 0)
Packit Service fdd496
		  {
Packit Service fdd496
		    execvp (editor_program, (char **) argv);
Packit Service fdd496
		    _exit (errno == ENOENT ? 127 : 126);
Packit Service fdd496
		  }
Packit Service fdd496
Packit Service fdd496
		if (pid < 0)
Packit Service fdd496
		  perror_fatal ("fork");
Packit Service fdd496
Packit Service fdd496
		while (waitpid (pid, &wstatus, 0) < 0)
Packit Service fdd496
		  if (errno == EINTR)
Packit Service fdd496
		    checksigs ();
Packit Service fdd496
		  else
Packit Service fdd496
		    perror_fatal ("waitpid");
Packit Service fdd496
#endif
Packit Service fdd496
	      }
Packit Service fdd496
Packit Service fdd496
	      ignore_SIGINT = false;
Packit Service fdd496
	      check_child_status (werrno, wstatus, EXIT_SUCCESS,
Packit Service fdd496
				  editor_program);
Packit Service fdd496
	    }
Packit Service fdd496
Packit Service fdd496
	    {
Packit Service fdd496
	      char buf[SDIFF_BUFSIZE];
Packit Service fdd496
	      size_t size;
Packit Service fdd496
	      tmp = ck_fopen (tmpname, "r");
Packit Service fdd496
	      while ((size = ck_fread (buf, SDIFF_BUFSIZE, tmp)) != 0)
Packit Service fdd496
		{
Packit Service fdd496
		  checksigs ();
Packit Service fdd496
		  ck_fwrite (buf, size, outfile);
Packit Service fdd496
		}
Packit Service fdd496
	      ck_fclose (tmp);
Packit Service fdd496
	    }
Packit Service fdd496
	    return true;
Packit Service fdd496
	  }
Packit Service fdd496
	default:
Packit Service fdd496
	  give_help ();
Packit Service fdd496
	  break;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496

Packit Service fdd496
/* Alternately reveal bursts of diff output and handle user commands.  */
Packit Service fdd496
static bool
Packit Service fdd496
interact (struct line_filter *diff,
Packit Service fdd496
	  struct line_filter *left, char const *lname,
Packit Service fdd496
	  struct line_filter *right, char const *rname,
Packit Service fdd496
	  FILE *outfile)
Packit Service fdd496
{
Packit Service fdd496
  lin lline = 1, rline = 1;
Packit Service fdd496
Packit Service fdd496
  for (;;)
Packit Service fdd496
    {
Packit Service fdd496
      char diff_help[256];
Packit Service fdd496
      int snarfed = lf_snarf (diff, diff_help, sizeof diff_help);
Packit Service fdd496
Packit Service fdd496
      if (snarfed <= 0)
Packit Service fdd496
	return snarfed != 0;
Packit Service fdd496
Packit Service fdd496
      checksigs ();
Packit Service fdd496
Packit Service fdd496
      if (diff_help[0] == ' ')
Packit Service fdd496
	puts (diff_help + 1);
Packit Service fdd496
      else
Packit Service fdd496
	{
Packit Service fdd496
	  char *numend;
Packit Service fdd496
	  uintmax_t val;
Packit Service fdd496
	  lin llen, rlen, lenmax;
Packit Service fdd496
	  errno = 0;
Packit Service fdd496
	  val = strtoumax (diff_help + 1, &numend, 10);
Packit Service fdd496
	  if (LIN_MAX < val || errno || *numend != ',')
Packit Service fdd496
	    fatal (diff_help);
Packit Service fdd496
	  llen = val;
Packit Service fdd496
	  val = strtoumax (numend + 1, &numend, 10);
Packit Service fdd496
	  if (LIN_MAX < val || errno || *numend)
Packit Service fdd496
	    fatal (diff_help);
Packit Service fdd496
	  rlen = val;
Packit Service fdd496
Packit Service fdd496
	  lenmax = MAX (llen, rlen);
Packit Service fdd496
Packit Service fdd496
	  switch (diff_help[0])
Packit Service fdd496
	    {
Packit Service fdd496
	    case 'i':
Packit Service fdd496
	      if (suppress_common_lines)
Packit Service fdd496
		lf_skip (diff, lenmax);
Packit Service fdd496
	      else
Packit Service fdd496
		lf_copy (diff, lenmax, stdout);
Packit Service fdd496
Packit Service fdd496
	      lf_copy (left, llen, outfile);
Packit Service fdd496
	      lf_skip (right, rlen);
Packit Service fdd496
	      break;
Packit Service fdd496
Packit Service fdd496
	    case 'c':
Packit Service fdd496
	      lf_copy (diff, lenmax, stdout);
Packit Service fdd496
	      if (! edit (left, lname, lline, llen,
Packit Service fdd496
			  right, rname, rline, rlen,
Packit Service fdd496
			  outfile))
Packit Service fdd496
		return false;
Packit Service fdd496
	      break;
Packit Service fdd496
Packit Service fdd496
	    default:
Packit Service fdd496
	      fatal (diff_help);
Packit Service fdd496
	    }
Packit Service fdd496
Packit Service fdd496
	  lline += llen;
Packit Service fdd496
	  rline += rlen;
Packit Service fdd496
	}
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Return true if DIR is an existing directory.  */
Packit Service fdd496
static bool
Packit Service fdd496
diraccess (char const *dir)
Packit Service fdd496
{
Packit Service fdd496
  struct stat buf;
Packit Service fdd496
  return stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
#ifndef P_tmpdir
Packit Service fdd496
# define P_tmpdir "/tmp"
Packit Service fdd496
#endif
Packit Service fdd496
#ifndef TMPDIR_ENV
Packit Service fdd496
# define TMPDIR_ENV "TMPDIR"
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/* Open a temporary file and return its file descriptor.  Put into
Packit Service fdd496
   tmpname the address of a newly allocated buffer that holds the
Packit Service fdd496
   file's name.  Use the prefix "sdiff".  */
Packit Service fdd496
static int
Packit Service fdd496
temporary_file (void)
Packit Service fdd496
{
Packit Service fdd496
  char const *tmpdir = getenv (TMPDIR_ENV);
Packit Service fdd496
  char const *dir = tmpdir ? tmpdir : P_tmpdir;
Packit Service fdd496
  char *buf = xmalloc (strlen (dir) + 1 + 5 + 6 + 1);
Packit Service fdd496
  int fd;
Packit Service fdd496
  sprintf (buf, "%s/sdiffXXXXXX", dir);
Packit Service fdd496
  fd = mkstemp (buf);
Packit Service fdd496
  if (0 <= fd)
Packit Service fdd496
    tmpname = buf;
Packit Service fdd496
  return fd;
Packit Service fdd496
}