summaryrefslogtreecommitdiff
path: root/gnu/dist/diffutils/src/sdiff.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/dist/diffutils/src/sdiff.c')
-rw-r--r--gnu/dist/diffutils/src/sdiff.c1225
1 files changed, 0 insertions, 1225 deletions
diff --git a/gnu/dist/diffutils/src/sdiff.c b/gnu/dist/diffutils/src/sdiff.c
deleted file mode 100644
index b69fecec789..00000000000
--- a/gnu/dist/diffutils/src/sdiff.c
+++ /dev/null
@@ -1,1225 +0,0 @@
-/* $NetBSD: sdiff.c,v 1.2 2006/02/18 22:42:12 apb Exp $ */
-
-/* sdiff - side-by-side merge of file differences
-
- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 2001, 2002 Free
- Software Foundation, Inc.
-
- This file is part of GNU DIFF.
-
- GNU DIFF is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GNU DIFF is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING.
- If not, write to the Free Software Foundation,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include "system.h"
-
-#include <c-stack.h>
-#include <dirname.h>
-#include <error.h>
-#include <exitfail.h>
-#include <freesoft.h>
-#include <getopt.h>
-#include <quotesys.h>
-#include <stdio.h>
-#include <xalloc.h>
-
-static char const authorship_msgid[] = N_("Written by Thomas Lord.");
-
-static char const copyright_string[] =
- "Copyright (C) 2002 Free Software Foundation, Inc.";
-
-extern char const version_string[];
-
-/* Size of chunks read from files which must be parsed into lines. */
-#define SDIFF_BUFSIZE ((size_t) 65536)
-
-char *program_name;
-
-static char const *editor_program = DEFAULT_EDITOR_PROGRAM;
-static char const **diffargv;
-
-static char * volatile tmpname;
-static FILE *tmp;
-
-#if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
-static pid_t volatile diffpid;
-#endif
-
-struct line_filter;
-
-static RETSIGTYPE catchsig (int);
-static bool edit (struct line_filter *, char const *, lin, lin, struct line_filter *, char const *, lin, lin, FILE *);
-static bool interact (struct line_filter *, struct line_filter *, char const *, struct line_filter *, char const *, FILE *);
-static void checksigs (void);
-static void diffarg (char const *);
-static void fatal (char const *) __attribute__((noreturn));
-static void perror_fatal (char const *) __attribute__((noreturn));
-static void trapsigs (void);
-static void untrapsig (int);
-
-#define NUM_SIGS (sizeof sigs / sizeof *sigs)
-static int const sigs[] = {
-#ifdef SIGHUP
- SIGHUP,
-#endif
-#ifdef SIGQUIT
- SIGQUIT,
-#endif
-#ifdef SIGTERM
- SIGTERM,
-#endif
-#ifdef SIGXCPU
- SIGXCPU,
-#endif
-#ifdef SIGXFSZ
- SIGXFSZ,
-#endif
- SIGINT,
- SIGPIPE
-};
-#define handler_index_of_SIGINT (NUM_SIGS - 2)
-#define handler_index_of_SIGPIPE (NUM_SIGS - 1)
-
-#if HAVE_SIGACTION
- /* Prefer `sigaction' if available, since `signal' can lose signals. */
- static struct sigaction initial_action[NUM_SIGS];
-# define initial_handler(i) (initial_action[i].sa_handler)
- static void signal_handler (int, RETSIGTYPE (*) (int));
-#else
- static RETSIGTYPE (*initial_action[NUM_SIGS]) ();
-# define initial_handler(i) (initial_action[i])
-# define signal_handler(sig, handler) signal (sig, handler)
-#endif
-
-#if ! HAVE_SIGPROCMASK
-# define sigset_t int
-# define sigemptyset(s) (*(s) = 0)
-# ifndef sigmask
-# define sigmask(sig) (1 << ((sig) - 1))
-# endif
-# define sigaddset(s, sig) (*(s) |= sigmask (sig))
-# ifndef SIG_BLOCK
-# define SIG_BLOCK 0
-# endif
-# ifndef SIG_SETMASK
-# define SIG_SETMASK (! SIG_BLOCK)
-# endif
-# define sigprocmask(how, n, o) \
- ((how) == SIG_BLOCK ? *(o) = sigblock (*(n)) : sigsetmask (*(n)))
-#endif
-
-static bool diraccess (char const *);
-static int temporary_file (void);
-
-/* Options: */
-
-/* Name of output file if -o specified. */
-static char const *output;
-
-/* Do not print common lines. */
-static bool suppress_common_lines;
-
-/* Value for the long option that does not have single-letter equivalents. */
-enum
-{
- DIFF_PROGRAM_OPTION = CHAR_MAX + 1,
- HELP_OPTION,
- STRIP_TRAILING_CR_OPTION
-};
-
-static struct option const longopts[] =
-{
- {"diff-program", 1, 0, DIFF_PROGRAM_OPTION},
- {"expand-tabs", 0, 0, 't'},
- {"help", 0, 0, HELP_OPTION},
- {"ignore-all-space", 0, 0, 'W'}, /* swap W and w for historical reasons */
- {"ignore-blank-lines", 0, 0, 'B'},
- {"ignore-case", 0, 0, 'i'},
- {"ignore-matching-lines", 1, 0, 'I'},
- {"ignore-space-change", 0, 0, 'b'},
- {"ignore-tab-expansion", 0, 0, 'E'},
- {"left-column", 0, 0, 'l'},
- {"minimal", 0, 0, 'd'},
- {"output", 1, 0, 'o'},
- {"speed-large-files", 0, 0, 'H'},
- {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},
- {"suppress-common-lines", 0, 0, 's'},
- {"text", 0, 0, 'a'},
- {"version", 0, 0, 'v'},
- {"width", 1, 0, 'w'},
- {0, 0, 0, 0}
-};
-
-static void try_help (char const *, char const *) __attribute__((noreturn));
-static void
-try_help (char const *reason_msgid, char const *operand)
-{
- if (reason_msgid)
- error (0, 0, _(reason_msgid), operand);
- error (EXIT_TROUBLE, 0, _("Try `%s --help' for more information."),
- program_name);
- abort ();
-}
-
-static void
-check_stdout (void)
-{
- if (ferror (stdout))
- fatal ("write failed");
- else if (fclose (stdout) != 0)
- perror_fatal (_("standard output"));
-}
-
-static char const * const option_help_msgid[] = {
- N_("-o FILE --output=FILE Operate interactively, sending output to FILE."),
- "",
- N_("-i --ignore-case Consider upper- and lower-case to be the same."),
- N_("-E --ignore-tab-expansion Ignore changes due to tab expansion."),
- N_("-b --ignore-space-change Ignore changes in the amount of white space."),
- N_("-W --ignore-all-space Ignore all white space."),
- N_("-B --ignore-blank-lines Ignore changes whose lines are all blank."),
- N_("-I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE."),
- N_("--strip-trailing-cr Strip trailing carriage return on input."),
- N_("-a --text Treat all files as text."),
- "",
- N_("-w NUM --width=NUM Output at most NUM (default 130) columns per line."),
- N_("-l --left-column Output only the left column of common lines."),
- N_("-s --suppress-common-lines Do not output common lines."),
- "",
- N_("-t --expand-tabs Expand tabs to spaces in output."),
- "",
- N_("-d --minimal Try hard to find a smaller set of changes."),
- N_("-H --speed-large-files Assume large files and many scattered small changes."),
- N_("--diff-program=PROGRAM Use PROGRAM to compare files."),
- "",
- N_("-v --version Output version info."),
- N_("--help Output this help."),
- 0
-};
-
-static void
-usage (void)
-{
- char const * const *p;
-
- printf (_("Usage: %s [OPTION]... FILE1 FILE2\n"), program_name);
- printf ("%s\n\n", _("Side-by-side merge of file differences."));
- for (p = option_help_msgid; *p; p++)
- if (**p)
- printf (" %s\n", _(*p));
- else
- putchar ('\n');
- printf ("\n%s\n\n%s\n",
- _("If a FILE is `-', read standard input."),
- _("Report bugs to <bug-gnu-utils@gnu.org>."));
-}
-
-static void
-cleanup (void)
-{
-#if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
- if (0 < diffpid)
- kill (diffpid, SIGPIPE);
-#endif
- if (tmpname)
- unlink (tmpname);
-}
-
-static void exiterr (void) __attribute__((noreturn));
-static void
-exiterr (void)
-{
- cleanup ();
- untrapsig (0);
- checksigs ();
- exit (EXIT_TROUBLE);
-}
-
-static void
-fatal (char const *msgid)
-{
- error (0, 0, "%s", _(msgid));
- exiterr ();
-}
-
-static void
-perror_fatal (char const *msg)
-{
- int e = errno;
- checksigs ();
- error (0, e, "%s", msg);
- exiterr ();
-}
-
-static void
-check_child_status (int werrno, int wstatus, int max_ok_status,
- char const *subsidiary_program)
-{
- int status = (! werrno && WIFEXITED (wstatus)
- ? WEXITSTATUS (wstatus)
- : INT_MAX);
-
- if (max_ok_status < status)
- {
- error (0, werrno,
- _(status == 126
- ? "subsidiary program `%s' could not be invoked"
- : status == 127
- ? "subsidiary program `%s' not found"
- : status == INT_MAX
- ? "subsidiary program `%s' failed"
- : "subsidiary program `%s' failed (exit status %d)"),
- subsidiary_program, status);
- exiterr ();
- }
-}
-
-static FILE *
-ck_fopen (char const *fname, char const *type)
-{
- FILE *r = fopen (fname, type);
- if (! r)
- perror_fatal (fname);
- return r;
-}
-
-static void
-ck_fclose (FILE *f)
-{
- if (fclose (f))
- perror_fatal ("fclose");
-}
-
-static size_t
-ck_fread (char *buf, size_t size, FILE *f)
-{
- size_t r = fread (buf, sizeof (char), size, f);
- if (r == 0 && ferror (f))
- perror_fatal (_("read failed"));
- return r;
-}
-
-static void
-ck_fwrite (char const *buf, size_t size, FILE *f)
-{
- if (fwrite (buf, sizeof (char), size, f) != size)
- perror_fatal (_("write failed"));
-}
-
-static void
-ck_fflush (FILE *f)
-{
- if (fflush (f) != 0)
- perror_fatal (_("write failed"));
-}
-
-static char const *
-expand_name (char *name, bool is_dir, char const *other_name)
-{
- if (strcmp (name, "-") == 0)
- fatal ("cannot interactively merge standard input");
- if (! is_dir)
- return name;
- else
- {
- /* Yield NAME/BASE, where BASE is OTHER_NAME's basename. */
- char const *base = base_name (other_name);
- size_t namelen = strlen (name), baselen = strlen (base);
- bool insert_slash = *base_name (name) && name[namelen - 1] != '/';
- char *r = xmalloc (namelen + insert_slash + baselen + 1);
- memcpy (r, name, namelen);
- r[namelen] = '/';
- memcpy (r + namelen + insert_slash, base, baselen + 1);
- return r;
- }
-}
-
-
-
-struct line_filter {
- FILE *infile;
- char *bufpos;
- char *buffer;
- char *buflim;
-};
-
-static void
-lf_init (struct line_filter *lf, FILE *infile)
-{
- lf->infile = infile;
- lf->bufpos = lf->buffer = lf->buflim = xmalloc (SDIFF_BUFSIZE + 1);
- lf->buflim[0] = '\n';
-}
-
-/* Fill an exhausted line_filter buffer from its INFILE */
-static size_t
-lf_refill (struct line_filter *lf)
-{
- size_t s = ck_fread (lf->buffer, SDIFF_BUFSIZE, lf->infile);
- lf->bufpos = lf->buffer;
- lf->buflim = lf->buffer + s;
- lf->buflim[0] = '\n';
- checksigs ();
- return s;
-}
-
-/* Advance LINES on LF's infile, copying lines to OUTFILE */
-static void
-lf_copy (struct line_filter *lf, lin lines, FILE *outfile)
-{
- char *start = lf->bufpos;
-
- while (lines)
- {
- lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
- if (! lf->bufpos)
- {
- ck_fwrite (start, lf->buflim - start, outfile);
- if (! lf_refill (lf))
- return;
- start = lf->bufpos;
- }
- else
- {
- --lines;
- ++lf->bufpos;
- }
- }
-
- ck_fwrite (start, lf->bufpos - start, outfile);
-}
-
-/* Advance LINES on LF's infile without doing output */
-static void
-lf_skip (struct line_filter *lf, lin lines)
-{
- while (lines)
- {
- lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
- if (! lf->bufpos)
- {
- if (! lf_refill (lf))
- break;
- }
- else
- {
- --lines;
- ++lf->bufpos;
- }
- }
-}
-
-/* Snarf a line into a buffer. Return EOF if EOF, 0 if error, 1 if OK. */
-static int
-lf_snarf (struct line_filter *lf, char *buffer, size_t bufsize)
-{
- for (;;)
- {
- char *start = lf->bufpos;
- char *next = (char *) memchr (start, '\n', lf->buflim + 1 - start);
- size_t s = next - start;
- if (bufsize <= s)
- return 0;
- memcpy (buffer, start, s);
- if (next < lf->buflim)
- {
- buffer[s] = 0;
- lf->bufpos = next + 1;
- return 1;
- }
- if (! lf_refill (lf))
- return s ? 0 : EOF;
- buffer += s;
- bufsize -= s;
- }
-}
-
-
-
-int
-main (int argc, char *argv[])
-{
- int opt;
- char const *prog;
-
- exit_failure = EXIT_TROUBLE;
- initialize_main (&argc, &argv);
- program_name = argv[0];
- setlocale (LC_ALL, "");
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
- c_stack_action (c_stack_die);
-
- prog = getenv ("EDITOR");
- if (prog)
- editor_program = prog;
-
- diffarg (DEFAULT_DIFF_PROGRAM);
-
- /* parse command line args */
- while ((opt = getopt_long (argc, argv, "abBdHiI:lo:stvw:W", longopts, 0))
- != -1)
- {
- switch (opt)
- {
- case 'a':
- diffarg ("-a");
- break;
-
- case 'b':
- diffarg ("-b");
- break;
-
- case 'B':
- diffarg ("-B");
- break;
-
- case 'd':
- diffarg ("-d");
- break;
-
- case 'E':
- diffarg ("-E");
- break;
-
- case 'H':
- diffarg ("-H");
- break;
-
- case 'i':
- diffarg ("-i");
- break;
-
- case 'I':
- diffarg ("-I");
- diffarg (optarg);
- break;
-
- case 'l':
- diffarg ("--left-column");
- break;
-
- case 'o':
- output = optarg;
- break;
-
- case 's':
- suppress_common_lines = 1;
- break;
-
- case 't':
- diffarg ("-t");
- break;
-
- case 'v':
- printf ("sdiff %s\n%s\n\n%s\n\n%s\n",
- version_string, copyright_string,
- _(free_software_msgid), _(authorship_msgid));
- check_stdout ();
- return EXIT_SUCCESS;
-
- case 'w':
- diffarg ("-W");
- diffarg (optarg);
- break;
-
- case 'W':
- diffarg ("-w");
- break;
-
- case DIFF_PROGRAM_OPTION:
- diffargv[0] = optarg;
- break;
-
- case HELP_OPTION:
- usage ();
- check_stdout ();
- return EXIT_SUCCESS;
-
- case STRIP_TRAILING_CR_OPTION:
- diffarg ("--strip-trailing-cr");
- break;
-
- default:
- try_help (0, 0);
- }
- }
-
- if (argc - optind != 2)
- {
- if (argc - optind < 2)
- try_help ("missing operand after `%s'", argv[argc - 1]);
- else
- try_help ("extra operand `%s'", argv[optind + 2]);
- }
-
- if (! output)
- {
- /* easy case: diff does everything for us */
- if (suppress_common_lines)
- diffarg ("--suppress-common-lines");
- diffarg ("-y");
- diffarg ("--");
- diffarg (argv[optind]);
- diffarg (argv[optind + 1]);
- diffarg (0);
- execvp (diffargv[0], (char **) diffargv);
- perror_fatal (diffargv[0]);
- }
- else
- {
- char const *lname, *rname;
- FILE *left, *right, *out, *diffout;
- bool interact_ok;
- struct line_filter lfilt;
- struct line_filter rfilt;
- struct line_filter diff_filt;
- bool leftdir = diraccess (argv[optind]);
- bool rightdir = diraccess (argv[optind + 1]);
-
- if (leftdir & rightdir)
- fatal ("both files to be compared are directories");
-
- lname = expand_name (argv[optind], leftdir, argv[optind + 1]);
- left = ck_fopen (lname, "r");
- rname = expand_name (argv[optind + 1], rightdir, argv[optind]);
- right = ck_fopen (rname, "r");
- out = ck_fopen (output, "w");
-
- diffarg ("--sdiff-merge-assist");
- diffarg ("--");
- diffarg (argv[optind]);
- diffarg (argv[optind + 1]);
- diffarg (0);
-
- trapsigs ();
-
-#if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
- {
- size_t cmdsize = 1;
- char *p, *command;
- int i;
-
- for (i = 0; diffargv[i]; i++)
- cmdsize += quote_system_arg (0, diffargv[i]) + 1;
- command = p = xmalloc (cmdsize);
- for (i = 0; diffargv[i]; i++)
- {
- p += quote_system_arg (p, diffargv[i]);
- *p++ = ' ';
- }
- p[-1] = 0;
- errno = 0;
- diffout = popen (command, "r");
- if (! diffout)
- perror_fatal (command);
- free (command);
- }
-#else
- {
- int diff_fds[2];
-# if HAVE_WORKING_VFORK
- sigset_t procmask;
- sigset_t blocked;
-# endif
-
- if (pipe (diff_fds) != 0)
- perror_fatal ("pipe");
-
-# if HAVE_WORKING_VFORK
- /* Block SIGINT and SIGPIPE. */
- sigemptyset (&blocked);
- sigaddset (&blocked, SIGINT);
- sigaddset (&blocked, SIGPIPE);
- sigprocmask (SIG_BLOCK, &blocked, &procmask);
-# endif
- diffpid = vfork ();
- if (diffpid < 0)
- perror_fatal ("fork");
- if (! diffpid)
- {
- /* Alter the child's SIGINT and SIGPIPE handlers;
- this may munge the parent.
- The child ignores SIGINT in case the user interrupts the editor.
- The child does not ignore SIGPIPE, even if the parent does. */
- if (initial_handler (handler_index_of_SIGINT) != SIG_IGN)
- signal_handler (SIGINT, SIG_IGN);
- signal_handler (SIGPIPE, SIG_DFL);
-# if HAVE_WORKING_VFORK
- /* Stop blocking SIGINT and SIGPIPE in the child. */
- sigprocmask (SIG_SETMASK, &procmask, 0);
-# endif
- close (diff_fds[0]);
- if (diff_fds[1] != STDOUT_FILENO)
- {
- dup2 (diff_fds[1], STDOUT_FILENO);
- close (diff_fds[1]);
- }
-
- execvp (diffargv[0], (char **) diffargv);
- _exit (errno == ENOEXEC ? 126 : 127);
- }
-
-# if HAVE_WORKING_VFORK
- /* Restore the parent's SIGINT and SIGPIPE behavior. */
- if (initial_handler (handler_index_of_SIGINT) != SIG_IGN)
- signal_handler (SIGINT, catchsig);
- if (initial_handler (handler_index_of_SIGPIPE) != SIG_IGN)
- signal_handler (SIGPIPE, catchsig);
- else
- signal_handler (SIGPIPE, SIG_IGN);
-
- /* Stop blocking SIGINT and SIGPIPE in the parent. */
- sigprocmask (SIG_SETMASK, &procmask, 0);
-# endif
-
- close (diff_fds[1]);
- diffout = fdopen (diff_fds[0], "r");
- if (! diffout)
- perror_fatal ("fdopen");
- }
-#endif
-
- lf_init (&diff_filt, diffout);
- lf_init (&lfilt, left);
- lf_init (&rfilt, right);
-
- interact_ok = interact (&diff_filt, &lfilt, lname, &rfilt, rname, out);
-
- ck_fclose (left);
- ck_fclose (right);
- ck_fclose (out);
-
- {
- int wstatus;
- int werrno = 0;
-
-#if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
- wstatus = pclose (diffout);
- if (wstatus == -1)
- werrno = errno;
-#else
- ck_fclose (diffout);
- while (waitpid (diffpid, &wstatus, 0) < 0)
- if (errno == EINTR)
- checksigs ();
- else
- perror_fatal ("waitpid");
- diffpid = 0;
-#endif
-
- if (tmpname)
- {
- unlink (tmpname);
- tmpname = 0;
- }
-
- if (! interact_ok)
- exiterr ();
-
- check_child_status (werrno, wstatus, EXIT_FAILURE, diffargv[0]);
- untrapsig (0);
- checksigs ();
- exit (WEXITSTATUS (wstatus));
- }
- }
- return EXIT_SUCCESS; /* Fool `-Wall'. */
-}
-
-static void
-diffarg (char const *a)
-{
- static size_t diffargs, diffarglim;
-
- if (diffargs == diffarglim)
- {
- if (! diffarglim)
- diffarglim = 16;
- else if (PTRDIFF_MAX / (2 * sizeof *diffargv) <= diffarglim)
- xalloc_die ();
- else
- diffarglim *= 2;
- diffargv = xrealloc (diffargv, diffarglim * sizeof *diffargv);
- }
- diffargv[diffargs++] = a;
-}
-
-
-
-
-/* Signal handling */
-
-static bool volatile ignore_SIGINT;
-static int volatile signal_received;
-static bool sigs_trapped;
-
-static RETSIGTYPE
-catchsig (int s)
-{
-#if ! HAVE_SIGACTION
- signal (s, SIG_IGN);
-#endif
- if (! (s == SIGINT && ignore_SIGINT))
- signal_received = s;
-}
-
-#if HAVE_SIGACTION
-static struct sigaction catchaction;
-
-static void
-signal_handler (int sig, RETSIGTYPE (*handler) (int))
-{
- catchaction.sa_handler = handler;
- sigaction (sig, &catchaction, 0);
-}
-#endif
-
-static void
-trapsigs (void)
-{
- int i;
-
-#if HAVE_SIGACTION
- catchaction.sa_flags = SA_RESTART;
- sigemptyset (&catchaction.sa_mask);
- for (i = 0; i < NUM_SIGS; i++)
- sigaddset (&catchaction.sa_mask, sigs[i]);
-#endif
-
- for (i = 0; i < NUM_SIGS; i++)
- {
-#if HAVE_SIGACTION
- sigaction (sigs[i], 0, &initial_action[i]);
-#else
- initial_action[i] = signal (sigs[i], SIG_IGN);
-#endif
- if (initial_handler (i) != SIG_IGN)
- signal_handler (sigs[i], catchsig);
- }
-
-#ifdef SIGCHLD
- /* System V fork+wait does not work if SIGCHLD is ignored. */
- signal (SIGCHLD, SIG_DFL);
-#endif
-
- sigs_trapped = 1;
-}
-
-/* Untrap signal S, or all trapped signals if S is zero. */
-static void
-untrapsig (int s)
-{
- int i;
-
- if (sigs_trapped)
- for (i = 0; i < NUM_SIGS; i++)
- if ((! s || sigs[i] == s) && initial_handler (i) != SIG_IGN)
-#if HAVE_SIGACTION
- sigaction (sigs[i], &initial_action[i], 0);
-#else
- signal (sigs[i], initial_action[i]);
-#endif
-}
-
-/* Exit if a signal has been received. */
-static void
-checksigs (void)
-{
- int s = signal_received;
- if (s)
- {
- cleanup ();
-
- /* Yield an exit status indicating that a signal was received. */
- untrapsig (s);
- kill (getpid (), s);
-
- /* That didn't work, so exit with error status. */
- exit (EXIT_TROUBLE);
- }
-}
-
-
-static void
-give_help (void)
-{
- fprintf (stderr, "%s", _("\
-ed:\tEdit then use both versions, each decorated with a header.\n\
-eb:\tEdit then use both versions.\n\
-el:\tEdit then use the left version.\n\
-er:\tEdit then use the right version.\n\
-e:\tEdit a new version.\n\
-l:\tUse the left version.\n\
-r:\tUse the right version.\n\
-s:\tSilently include common lines.\n\
-v:\tVerbosely include common lines.\n\
-q:\tQuit.\n\
-"));
-}
-
-static int
-skip_white (void)
-{
- int c;
- for (;;)
- {
- c = getchar ();
- if (! ISSPACE (c) || c == '\n')
- break;
- checksigs ();
- }
- if (ferror (stdin))
- perror_fatal (_("read failed"));
- return c;
-}
-
-static void
-flush_line (void)
-{
- int c;
- while ((c = getchar ()) != '\n' && c != EOF)
- continue;
- if (ferror (stdin))
- perror_fatal (_("read failed"));
-}
-
-
-/* interpret an edit command */
-static bool
-edit (struct line_filter *left, char const *lname, lin lline, lin llen,
- struct line_filter *right, char const *rname, lin rline, lin rlen,
- FILE *outfile)
-{
- for (;;)
- {
- int cmd0, cmd1;
- bool gotcmd = 0;
-
- cmd1 = 0; /* Pacify `gcc -W'. */
-
- while (! gotcmd)
- {
- if (putchar ('%') != '%')
- perror_fatal (_("write failed"));
- ck_fflush (stdout);
-
- cmd0 = skip_white ();
- switch (cmd0)
- {
- case 'l': case 'r': case 's': case 'v': case 'q':
- if (skip_white () != '\n')
- {
- give_help ();
- flush_line ();
- continue;
- }
- gotcmd = 1;
- break;
-
- case 'e':
- cmd1 = skip_white ();
- switch (cmd1)
- {
- case 'b': case 'd': case 'l': case 'r':
- if (skip_white () != '\n')
- {
- give_help ();
- flush_line ();
- continue;
- }
- gotcmd = 1;
- break;
- case '\n':
- gotcmd = 1;
- break;
- default:
- give_help ();
- flush_line ();
- continue;
- }
- break;
-
- case EOF:
- if (feof (stdin))
- {
- gotcmd = 1;
- cmd0 = 'q';
- break;
- }
- /* Fall through. */
- default:
- flush_line ();
- /* Fall through. */
- case '\n':
- give_help ();
- continue;
- }
- }
-
- switch (cmd0)
- {
- case 'l':
- lf_copy (left, llen, outfile);
- lf_skip (right, rlen);
- return 1;
- case 'r':
- lf_copy (right, rlen, outfile);
- lf_skip (left, llen);
- return 1;
- case 's':
- suppress_common_lines = 1;
- break;
- case 'v':
- suppress_common_lines = 0;
- break;
- case 'q':
- return 0;
- case 'e':
- {
- int fd;
-
- if (tmpname)
- tmp = fopen (tmpname, "w");
- else
- {
- if ((fd = temporary_file ()) < 0)
- perror_fatal ("mkstemp");
- tmp = fdopen (fd, "w");
- }
-
- if (! tmp)
- perror_fatal (tmpname);
-
- switch (cmd1)
- {
- case 'd':
- if (llen)
- {
- if (llen == 1)
- fprintf (tmp, "--- %s %ld\n", lname, (long) lline);
- else
- fprintf (tmp, "--- %s %ld,%ld\n", lname,
- (long) lline, (long) (lline + llen - 1));
- }
- /* Fall through. */
- case 'b': case 'l':
- lf_copy (left, llen, tmp);
- break;
-
- default:
- lf_skip (left, llen);
- break;
- }
-
- switch (cmd1)
- {
- case 'd':
- if (rlen)
- {
- if (rlen == 1)
- fprintf (tmp, "+++ %s %ld\n", rname, (long) rline);
- else
- fprintf (tmp, "+++ %s %ld,%ld\n", rname,
- (long) rline, (long) (rline + rlen - 1));
- }
- /* Fall through. */
- case 'b': case 'r':
- lf_copy (right, rlen, tmp);
- break;
-
- default:
- lf_skip (right, rlen);
- break;
- }
-
- ck_fclose (tmp);
-
- {
- int wstatus;
- int werrno = 0;
- ignore_SIGINT = 1;
- checksigs ();
-
- {
-#if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
- char *command =
- xmalloc (quote_system_arg (0, editor_program)
- + 1 + strlen (tmpname) + 1);
- sprintf (command + quote_system_arg (command, editor_program),
- " %s", tmpname);
- wstatus = system (command);
- if (wstatus == -1)
- werrno = errno;
- free (command);
-#else
- pid_t pid;
-
- pid = vfork ();
- if (pid == 0)
- {
- char const *argv[3];
- int i = 0;
-
- argv[i++] = editor_program;
- argv[i++] = tmpname;
- argv[i] = 0;
-
- execvp (editor_program, (char **) argv);
- _exit (errno == ENOEXEC ? 126 : 127);
- }
-
- if (pid < 0)
- perror_fatal ("fork");
-
- while (waitpid (pid, &wstatus, 0) < 0)
- if (errno == EINTR)
- checksigs ();
- else
- perror_fatal ("waitpid");
-#endif
- }
-
- ignore_SIGINT = 0;
- check_child_status (werrno, wstatus, EXIT_SUCCESS,
- editor_program);
- }
-
- {
- char buf[SDIFF_BUFSIZE];
- size_t size;
- tmp = ck_fopen (tmpname, "r");
- while ((size = ck_fread (buf, SDIFF_BUFSIZE, tmp)) != 0)
- {
- checksigs ();
- ck_fwrite (buf, size, outfile);
- }
- ck_fclose (tmp);
- }
- return 1;
- }
- default:
- give_help ();
- break;
- }
- }
-}
-
-
-
-/* Alternately reveal bursts of diff output and handle user commands. */
-static bool
-interact (struct line_filter *diff,
- struct line_filter *left, char const *lname,
- struct line_filter *right, char const *rname,
- FILE *outfile)
-{
- lin lline = 1, rline = 1;
-
- for (;;)
- {
- char diff_help[256];
- int snarfed = lf_snarf (diff, diff_help, sizeof diff_help);
-
- if (snarfed <= 0)
- return snarfed != 0;
-
- checksigs ();
-
- if (diff_help[0] == ' ')
- puts (diff_help + 1);
- else
- {
- char *numend;
- uintmax_t val;
- lin llen, rlen, lenmax;
- errno = 0;
- llen = val = strtoumax (diff_help + 1, &numend, 10);
- if (llen < 0 || llen != val || errno || *numend != ',')
- fatal (diff_help);
- rlen = val = strtoumax (numend + 1, &numend, 10);
- if (rlen < 0 || rlen != val || errno || *numend)
- fatal (diff_help);
-
- lenmax = MAX (llen, rlen);
-
- switch (diff_help[0])
- {
- case 'i':
- if (suppress_common_lines)
- lf_skip (diff, lenmax);
- else
- lf_copy (diff, lenmax, stdout);
-
- lf_copy (left, llen, outfile);
- lf_skip (right, rlen);
- break;
-
- case 'c':
- lf_copy (diff, lenmax, stdout);
- if (! edit (left, lname, lline, llen,
- right, rname, rline, rlen,
- outfile))
- return 0;
- break;
-
- default:
- fatal (diff_help);
- }
-
- lline += llen;
- rline += rlen;
- }
- }
-}
-
-/* Return nonzero if DIR is an existing directory. */
-static bool
-diraccess (char const *dir)
-{
- struct stat buf;
- return stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode);
-}
-
-#ifndef P_tmpdir
-# define P_tmpdir "/tmp"
-#endif
-#ifndef TMPDIR_ENV
-# define TMPDIR_ENV "TMPDIR"
-#endif
-
-/* Open a temporary file and return its file descriptor. Put into
- tmpname the address of a newly allocated buffer that holds the
- file's name. Use the prefix "sdiff". */
-static int
-temporary_file (void)
-{
- char const *tmpdir = getenv (TMPDIR_ENV);
- char const *dir = tmpdir ? tmpdir : P_tmpdir;
- char *buf = xmalloc (strlen (dir) + 1 + 5 + 6 + 1);
- int fd;
- int e;
- sigset_t procmask;
- sigset_t blocked;
- sprintf (buf, "%s/sdiffXXXXXX", dir);
- sigemptyset (&blocked);
- sigaddset (&blocked, SIGINT);
- sigprocmask (SIG_BLOCK, &blocked, &procmask);
- fd = mkstemp (buf);
- e = errno;
- if (0 <= fd)
- tmpname = buf;
- sigprocmask (SIG_SETMASK, &procmask, 0);
- errno = e;
- return fd;
-}