summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/diff/diff3.c
diff options
context:
space:
mode:
authorjtc <jtc@NetBSD.org>1994-11-01 20:38:40 +0000
committerjtc <jtc@NetBSD.org>1994-11-01 20:38:40 +0000
commitcd439d82af9522ec662102dfebdc44875eb58bf4 (patch)
tree78fe55729c4ac3d1f789a33cc7e4612c390ce28b /gnu/usr.bin/diff/diff3.c
parent0f8e6cf96801bbae057bcf623b51ab7d71b765e4 (diff)
Upgraded to diffutils 2.7.
Diffstat (limited to 'gnu/usr.bin/diff/diff3.c')
-rw-r--r--gnu/usr.bin/diff/diff3.c191
1 files changed, 129 insertions, 62 deletions
diff --git a/gnu/usr.bin/diff/diff3.c b/gnu/usr.bin/diff/diff3.c
index 5fabe0c3181..5d94ab866db 100644
--- a/gnu/usr.bin/diff/diff3.c
+++ b/gnu/usr.bin/diff/diff3.c
@@ -1,5 +1,5 @@
/* Three way file comparison program (diff3) for Project GNU.
- Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,13 +17,9 @@
/* Written by Randy Smith */
-#ifndef lint
-static char *rcsid = "$Id: diff3.c,v 1.5 1993/11/12 02:25:59 jtc Exp $";
-#endif
-
#include "system.h"
#include <stdio.h>
-#include <ctype.h>
+#include <signal.h>
#include "getopt.h"
extern char const version_string[];
@@ -177,7 +173,7 @@ static int finalwrite;
/* If nonzero, output a merged file. */
static int merge;
-static char *argv0;
+static char *program_name;
static VOID *xmalloc PARAMS((size_t));
static VOID *xrealloc PARAMS((VOID *, size_t));
@@ -196,11 +192,13 @@ static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct di
static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *));
static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *));
static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **));
+static void check_stdout PARAMS((void));
static void fatal PARAMS((char const *));
static void output_diff3 PARAMS((FILE *, struct diff3_block *, int const[3], int const[3]));
static void perror_with_exit PARAMS((char const *));
+static void try_help PARAMS((char const *));
static void undotlines PARAMS((FILE *, int, int, int));
-static void usage PARAMS((int));
+static void usage PARAMS((void));
static char const diff_program[] = DIFF_PROGRAM;
@@ -232,7 +230,7 @@ main (argc, argv)
int c, i;
int mapping[3];
int rev_mapping[3];
- int incompat;
+ int incompat = 0;
int conflicts_found;
struct diff_block *thread0, *thread1, *last_block;
struct diff3_block *diff3;
@@ -242,9 +240,8 @@ main (argc, argv)
char **file;
struct stat statb;
- incompat = 0;
-
- argv0 = argv[0];
+ initialize_main (&argc, &argv);
+ program_name = argv[0];
while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF)
{
@@ -285,10 +282,12 @@ main (argc, argv)
tab_align_flag = 1;
break;
case 'v':
- printf ("GNU diff3 version %s\n", version_string);
+ printf ("diff3 - GNU diffutils version %s\n", version_string);
exit (0);
case 129:
- usage (0);
+ usage ();
+ check_stdout ();
+ exit (0);
case 'L':
/* Handle up to three -L options. */
if (tag_count < 3)
@@ -296,9 +295,9 @@ main (argc, argv)
tag_strings[tag_count++] = optarg;
break;
}
- /* Falls through */
+ try_help ("Too many labels were given. The limit is 3.");
default:
- usage (2);
+ try_help (0);
}
}
@@ -308,9 +307,11 @@ main (argc, argv)
if (incompat > 1 /* Ensure at most one of -AeExX3. */
|| finalwrite & merge /* -i -m would rewrite input file. */
- || (tag_count && ! flagging) /* -L requires one of -AEX. */
- || argc - optind != 3)
- usage (2);
+ || (tag_count && ! flagging)) /* -L requires one of -AEX. */
+ try_help ("incompatible options");
+
+ if (argc - optind != 3)
+ try_help (argc - optind < 3 ? "missing operand" : "extra operand");
file = &argv[optind];
@@ -353,11 +354,20 @@ main (argc, argv)
perror_with_exit (file[i]);
else if (S_ISDIR(statb.st_mode))
{
- fprintf (stderr, "%s: %s: Is a directory\n", argv0, file[i]);
+ fprintf (stderr, "%s: %s: Is a directory\n",
+ program_name, file[i]);
exit (2);
}
}
+#if !defined(SIGCHLD) && defined(SIGCLD)
+#define SIGCHLD SIGCLD
+#endif
+#ifdef SIGCHLD
+ /* System V fork+wait does not work if SIGCHLD is ignored. */
+ signal (SIGCHLD, SIG_DFL);
+#endif
+
commonname = file[rev_mapping[FILEC]];
thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
if (thread1)
@@ -388,29 +398,54 @@ main (argc, argv)
conflicts_found = 0;
}
- if (ferror (stdout) || fclose (stdout) != 0)
- fatal ("write error");
+ check_stdout ();
exit (conflicts_found);
return conflicts_found;
}
+static void
+try_help (reason)
+ char const *reason;
+{
+ if (reason)
+ fprintf (stderr, "%s: %s\n", program_name, reason);
+ fprintf (stderr, "%s: Try `%s --help' for more information.\n",
+ program_name, program_name);
+ exit (2);
+}
+
+static void
+check_stdout ()
+{
+ if (ferror (stdout) || fclose (stdout) != 0)
+ fatal ("write error");
+}
+
/*
- * Explain, patiently and kindly, how to use this program. Then exit.
+ * Explain, patiently and kindly, how to use this program.
*/
static void
-usage (status)
- int status;
+usage ()
{
- fflush (stderr);
- printf ("\
-Usage: %s [options] my-file older-file your-file\n\
-Options:\n\
- [-exAEX3aTv] [-i|-m] [-L label1 [-L label2 [-L label3]]]\n\
- [--easy-only] [--ed] [--help] [--initial-tab]\n\
- [--label=label1 [--label=label2 [--label=label3]]] [--merge]\n\
- [--overlap-only] [--show-all] [--show-overlap] [--text] [--version]\n\
- Only one of [exAEX3] is allowed\n", argv0);
- exit (status);
+ printf ("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n\n", program_name);
+
+ printf ("%s", "\
+ -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\
+ -E --show-overlap Output unmerged changes, bracketing conflicts.\n\
+ -A --show-all Output all changes, bracketing conflicts.\n\
+ -x --overlap-only Output overlapping changes.\n\
+ -X Output overlapping changes, bracketing them.\n\
+ -3 --easy-only Output unmerged nonoverlapping changes.\n\n");
+ printf ("%s", "\
+ -m --merge Output merged file instead of ed script (default -A).\n\
+ -L LABEL --label=LABEL Use LABEL instead of file name.\n\
+ -i Append `w' and `q' commands to ed scripts.\n\
+ -a --text Treat all files as text.\n\
+ -T --initial-tab Make tabs line up by prepending a tab.\n\n");
+ printf ("%s", "\
+ -v --version Output version info.\n\
+ --help Output this help.\n\n");
+ printf ("If a FILE is `-', read standard input.\n");
}
/*
@@ -900,8 +935,6 @@ compare_line_list (list1, lengths1, list2, lengths2, nl)
extern char **environ;
-#define DIFF_CHUNK_SIZE 10000
-
static struct diff_block *
process_diff (filea, fileb, last_block)
char const *filea, *fileb;
@@ -928,7 +961,7 @@ process_diff (filea, fileb, last_block)
dt = process_diff_control (&scan_diff, bptr);
if (dt == ERROR || *scan_diff != '\n')
{
- fprintf (stderr, "%s: diff error: ", argv0);
+ fprintf (stderr, "%s: diff error: ", program_name);
do
{
putc (*scan_diff, stderr);
@@ -1036,9 +1069,9 @@ process_diff_control (string, db)
#define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; }
#define READNUM(s, num) \
- { unsigned char c = *s; if (!isdigit (c)) return ERROR; holdnum = 0; \
+ { unsigned char c = *s; if (!ISDIGIT (c)) return ERROR; holdnum = 0; \
do { holdnum = (c - '0' + holdnum * 10); } \
- while (isdigit (c = *++s)); (num) = holdnum; }
+ while (ISDIGIT (c = *++s)); (num) = holdnum; }
/* Read first set of digits */
SKIPWHITE (s);
@@ -1100,12 +1133,20 @@ read_diff (filea, fileb, output_placement)
{
char *diff_result;
size_t bytes, current_chunk_size, total;
+ int fd, wstatus;
+ struct stat pipestat;
+
+ /* 302 / 1000 is log10(2.0) rounded up. Subtract 1 for the sign bit;
+ add 1 for integer division truncation; add 1 more for a minus sign. */
+#define INT_STRLEN_BOUND(type) ((sizeof(type)*CHAR_BIT - 1) * 302 / 1000 + 2)
+
+#if HAVE_FORK
+
char const *argv[7];
- char horizon_arg[256];
+ char horizon_arg[17 + INT_STRLEN_BOUND (int)];
char const **ap;
int fds[2];
pid_t pid;
- int wstatus;
ap = argv;
*ap++ = diff_program;
@@ -1118,8 +1159,8 @@ read_diff (filea, fileb, output_placement)
*ap++ = fileb;
*ap = 0;
- if (pipe (fds) < 0)
- perror_with_exit ("pipe failed");
+ if (pipe (fds) != 0)
+ perror_with_exit ("pipe");
pid = vfork ();
if (pid == 0)
@@ -1142,11 +1183,37 @@ read_diff (filea, fileb, output_placement)
perror_with_exit ("fork failed");
close (fds[1]); /* Prevent erroneous lack of EOF */
- current_chunk_size = DIFF_CHUNK_SIZE;
+ fd = fds[0];
+
+#else /* ! HAVE_FORK */
+
+ FILE *fpipe;
+ char *command = xmalloc (sizeof (diff_program) + 30 + INT_STRLEN_BOUND (int)
+ + 4 * (strlen (filea) + strlen (fileb)));
+ char *p;
+ sprintf (command, "%s -a --horizon-lines=%d -- ",
+ diff_program, horizon_lines);
+ p = command + strlen (command);
+ SYSTEM_QUOTE_ARG (p, filea);
+ *p++ = ' ';
+ SYSTEM_QUOTE_ARG (p, fileb);
+ *p = '\0';
+ fpipe = popen (command, "r");
+ if (!fpipe)
+ perror_with_exit (command);
+ free (command);
+ fd = fileno (fpipe);
+
+#endif /* ! HAVE_FORK */
+
+ current_chunk_size = 8 * 1024;
+ if (fstat (fd, &pipestat) == 0)
+ current_chunk_size = max (current_chunk_size, STAT_BLOCKSIZE (pipestat));
+
diff_result = xmalloc (current_chunk_size);
total = 0;
do {
- bytes = myread (fds[0],
+ bytes = myread (fd,
diff_result + total,
current_chunk_size - total);
total += bytes;
@@ -1167,18 +1234,18 @@ read_diff (filea, fileb, output_placement)
*output_placement = diff_result;
-#if HAVE_WAITPID
+#if ! HAVE_FORK
+
+ wstatus = pclose (fpipe);
+
+#else /* HAVE_FORK */
+
+ if (close (fd) != 0)
+ perror_with_exit ("pipe close");
if (waitpid (pid, &wstatus, 0) < 0)
perror_with_exit ("waitpid failed");
-#else
- for (;;) {
- pid_t w = wait (&wstatus);
- if (w < 0)
- perror_with_exit ("wait failed");
- if (w == pid)
- break;
- }
-#endif
+
+#endif /* HAVE_FORK */
if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
fatal ("subsidiary diff failed");
@@ -1195,15 +1262,15 @@ read_diff (filea, fileb, output_placement)
* are used as call-by-reference values.
*/
static char *
-scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar)
+scan_diff_line (scan_ptr, set_start, set_length, limit, leadingchar)
char *scan_ptr, **set_start;
size_t *set_length;
char *limit;
- char firstchar;
+ int leadingchar;
{
char *line_ptr;
- if (!(scan_ptr[0] == (firstchar)
+ if (!(scan_ptr[0] == leadingchar
&& scan_ptr[1] == ' '))
fatal ("invalid diff format; incorrect leading line chars");
@@ -1220,7 +1287,7 @@ scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar)
if (line_ptr < limit && *line_ptr == '\\')
{
if (edscript)
- fprintf (stderr, "%s:", argv0);
+ fprintf (stderr, "%s:", program_name);
else
--*set_length;
line_ptr++;
@@ -1695,7 +1762,7 @@ static void
fatal (string)
char const *string;
{
- fprintf (stderr, "%s: %s\n", argv0, string);
+ fprintf (stderr, "%s: %s\n", program_name, string);
exit (2);
}
@@ -1704,7 +1771,7 @@ perror_with_exit (string)
char const *string;
{
int e = errno;
- fprintf (stderr, "%s: ", argv0);
+ fprintf (stderr, "%s: ", program_name);
errno = e;
perror (string);
exit (2);