Blame src/sdiff.c

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