diff options
Diffstat (limited to 'gnu/dist/diffutils/src/sdiff.c')
| -rw-r--r-- | gnu/dist/diffutils/src/sdiff.c | 1225 |
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; -} |
