summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/diff3/diff3.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/diff3/diff3.c')
-rw-r--r--gnu/usr.bin/diff3/diff3.c1166
1 files changed, 585 insertions, 581 deletions
diff --git a/gnu/usr.bin/diff3/diff3.c b/gnu/usr.bin/diff3/diff3.c
index 6bf193019a2..b9952fc0a04 100644
--- a/gnu/usr.bin/diff3/diff3.c
+++ b/gnu/usr.bin/diff3/diff3.c
@@ -1,9 +1,9 @@
-/* Three-way file comparison program (diff3) for Project GNU
- Copyright (C) 1988, 1989 Free Software Foundation, Inc.
+/* Three way file comparison program (diff3) for Project GNU.
+ Copyright (C) 1988, 1989, 1992 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
- the Free Software Foundation; either version 1, or (at your option)
+ the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
@@ -14,72 +14,42 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
/* Written by Randy Smith */
-#ifdef __STDC__
+#if __STDC__
#define VOID void
#else
#define VOID char
#endif
-/*
- * Include files.
- */
#include <stdio.h>
#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef USG
-#include <fcntl.h>
-
-/* Define needed BSD functions in terms of sysV library. */
-
-#define bcmp(s1,s2,n) memcmp((s1),(s2),(n))
-#define bzero(s,n) memset((s),0,(n))
-
-#ifndef XENIX
-#define dup2(f,t) (close(t),fcntl((f),F_DUPFD,(t)))
-#endif
-
-#define vfork fork
-
-#else /* not USG */
-#include <sys/wait.h>
-#endif /* not USG */
-
-#ifndef WEXITSTATUS
-#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
-#undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */
-#endif
-#ifndef WIFEXITED
-#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
-#endif
-
-#ifdef sparc
-/* vfork clobbers registers on the Sparc, so don't use it. */
-#define vfork fork
-#endif
+#include "getopt.h"
+#include "system.h"
/*
* Internal data structures and macros for the diff3 program; includes
* data structures for both diff3 diffs and normal diffs.
*/
-/*
- * Different files within a diff
- */
+/* Different files within a three way diff. */
#define FILE0 0
#define FILE1 1
#define FILE2 2
/*
- * Three way diffs are build out of two two-way diffs; the file which
+ * A three way diff is built from two two-way diffs; the file which
* the two two-way diffs share is:
*/
-#define FILEC FILE0
+#define FILEC FILE2
+
+/*
+ * Different files within a two way diff.
+ * FC is the common file, FO the other file.
+ */
+#define FO 0
+#define FC 1
/* The ranges are indexed by */
#define START 0
@@ -96,19 +66,19 @@ enum diff_type {
DIFF_3RD /* Only the third */
};
-/* Two-way diff */
+/* Two way diff */
struct diff_block {
- int ranges[2][2]; /* Ranges are inclusive */
+ int ranges[2][2]; /* Ranges are inclusive */
char **lines[2]; /* The actual lines (may contain nulls) */
int *lengths[2]; /* Line lengths (including newlines, if any) */
struct diff_block *next;
};
-/* Three-way diff */
+/* Three way diff */
struct diff3_block {
enum diff_type correspond; /* Type of diff */
- int ranges[3][2]; /* Ranges are inclusive */
+ int ranges[3][2]; /* Ranges are inclusive */
char **lines[3]; /* The actual lines (may contain nulls) */
int *lengths[3]; /* Line lengths (including newlines, if any) */
struct diff3_block *next;
@@ -122,7 +92,7 @@ struct diff3_block {
#define D_HIGHLINE(diff, filenum) \
((diff)->ranges[filenum][END])
#define D_NUMLINES(diff, filenum) \
- (D_HIGHLINE((diff), (filenum)) - D_LOWLINE((diff), (filenum)) + 1)
+ (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
/*
* Access the line numbers in a file in a diff by relative line
@@ -130,9 +100,9 @@ struct diff3_block {
* are lvalues and can be used for assignment.
*/
#define D_RELNUM(diff, filenum, linenum) \
- (*((diff)->lines[filenum] + linenum))
+ ((diff)->lines[filenum][linenum])
#define D_RELLEN(diff, filenum, linenum) \
- (*((diff)->lengths[filenum] + linenum))
+ ((diff)->lengths[filenum][linenum])
/*
* And get at them directly, when that should be necessary.
@@ -172,106 +142,130 @@ struct diff3_block {
#define ALLOCATE(number, type) \
(type *) xmalloc ((number) * sizeof (type))
-/*
- * Options variables for flags set on command line.
- *
- * ALWAYS_TEXT: Treat all files as text files; never treat as binary.
- *
- * EDSCRIPT: Write out an ed script instead of the standard diff3 format.
- *
- * FLAGGING: Indicates that in the case of overlapping diffs (type
- * DIFF_ALL), the lines which would normally be deleted from file 1
- * should be preserved with a special flagging mechanism.
- *
- * DONT_WRITE_OVERLAP: 1 if information for overlapping diffs should
- * not be output.
- *
- * DONT_WRITE_SIMPLE: 1 if information for non-overlapping diffs
- * should not be output.
- *
- * FINALWRITE: 1 if a :wq should be included at the end of the script
- * to write out the file being edited.
- *
- * MERGE: output a merged file.
- */
-int always_text;
-int edscript;
-int flagging;
-int dont_write_overlap;
-int dont_write_simple;
-int finalwrite;
-int merge;
+/* Options variables for flags set on command line. */
-extern int optind;
+/* If nonzero, treat all files as text files, never as binary. */
+static int always_text;
-char *argv0;
+/* If nonzero, write out an ed script instead of the standard diff3 format. */
+static int edscript;
-/*
- * Forward function declarations.
- */
-struct diff_block *process_diff ();
-struct diff3_block *make_3way_diff ();
-void output_diff3 ();
-int output_diff3_edscript ();
-int output_diff3_merge ();
-void usage ();
+/* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
+ preserve the lines which would normally be deleted from
+ file 1 with a special flagging mechanism. */
+static int flagging;
+
+/* Number of lines to keep in identical prefix and suffix. */
+static int horizon_lines = 10;
+
+/* If nonzero, do not output information for overlapping diffs. */
+static int simple_only;
+
+/* If nonzero, do not output information for non-overlapping diffs. */
+static int overlap_only;
+
+/* If nonzero, show information for DIFF_2ND diffs. */
+static int show_2nd;
+
+/* If nonzero, include `:wq' at the end of the script
+ to write out the file being edited. */
+static int finalwrite;
-struct diff3_block *using_to_diff3_block ();
-int copy_stringlist ();
-struct diff3_block *create_diff3_block ();
-int compare_line_list ();
+/* If nonzero, output a merged file. */
+static int merge;
-char *read_diff ();
-enum diff_type process_diff_control ();
-char *scan_diff_line ();
+static char *argv0;
-struct diff3_block *reverse_diff3_blocklist ();
+/*
+ * Forward function declarations.
+ */
+static int myread ();
+static void fatal ();
+static void perror_with_exit ();
+static struct diff_block *process_diff ();
+static struct diff3_block *make_3way_diff ();
+static void output_diff3 ();
+static int output_diff3_edscript ();
+static int output_diff3_merge ();
+static void usage ();
+
+static struct diff3_block *using_to_diff3_block ();
+static int copy_stringlist ();
+static struct diff3_block *create_diff3_block ();
+static int compare_line_list ();
+
+static char *read_diff ();
+static enum diff_type process_diff_control ();
+static char *scan_diff_line ();
+
+static struct diff3_block *reverse_diff3_blocklist ();
VOID *xmalloc ();
-VOID *xrealloc ();
+static VOID *xrealloc ();
-char diff_program[] = DIFF_PROGRAM;
+static char diff_program[] = DIFF_PROGRAM;
+
+static struct option longopts[] =
+{
+ {"text", 0, NULL, 'a'},
+ {"show-all", 0, NULL, 'A'},
+ {"ed", 0, NULL, 'e'},
+ {"show-overlap", 0, NULL, 'E'},
+ {"label", 1, NULL, 'L'},
+ {"merge", 0, NULL, 'm'},
+ {"overlap-only", 0, NULL, 'x'},
+ {"easy-only", 0, NULL, '3'},
+ {"version", 0, NULL, 'v'},
+ {0, 0, 0, 0}
+};
/*
* Main program. Calls diff twice on two pairs of input files,
* combines the two diffs, and outputs them.
*/
+int
main (argc, argv)
int argc;
char **argv;
{
+ extern char *version_string;
int c, i;
int mapping[3];
int rev_mapping[3];
int incompat;
- int overlaps_found;
- struct diff_block *thread1, *thread2;
- struct diff3_block *diff;
+ int conflicts_found;
+ struct diff_block *thread0, *thread1, *last_block;
+ struct diff3_block *diff3;
int tag_count = 0;
- /* Element 0 is for file 0, element 1 is for file 2. */
- char *tag_strings[2];
+ char *tag_strings[3];
extern char *optarg;
char *commonname;
+ char **file;
struct stat statb;
incompat = 0;
- tag_strings[0] = tag_strings[1] = 0;
argv0 = argv[0];
-
- while ((c = getopt (argc, argv, "aeimx3EXL:")) != EOF)
+
+ while ((c = getopt_long (argc, argv, "aeimvx3AEXL:", longopts, (int *) 0))
+ != EOF)
{
switch (c)
{
case 'a':
always_text = 1;
break;
+ case 'A':
+ show_2nd = 1;
+ flagging = 1;
+ incompat++;
+ break;
case 'x':
- dont_write_simple = 1;
+ overlap_only = 1;
incompat++;
break;
case '3':
- dont_write_overlap = 1;
+ simple_only = 1;
incompat++;
break;
case 'i':
@@ -281,7 +275,7 @@ main (argc, argv)
merge = 1;
break;
case 'X':
- dont_write_simple = 1;
+ overlap_only = 1;
/* Falls through */
case 'E':
flagging = 1;
@@ -289,48 +283,55 @@ main (argc, argv)
case 'e':
incompat++;
break;
+ case 'v':
+ fprintf (stderr, "GNU diff3 version %s\n", version_string);
+ break;
case 'L':
- /* Handle one or two -L arguments. */
- if (tag_count < 2)
+ /* Handle up to three -L options. */
+ if (tag_count < 3)
{
tag_strings[tag_count++] = optarg;
break;
}
/* Falls through */
- case '?':
default:
usage ();
/* NOTREACHED */
}
}
- edscript = incompat & ~merge; /* -eExX3 without -m implies ed script. */
- flagging |= ~incompat & merge; /* -m without -eExX3 implies -E. */
+ edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */
+ show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */
+ flagging |= ~incompat & merge;
- if (incompat > 1 /* Ensure at most one of -eExX3. */
- || finalwrite & (~incompat | merge)
- /* -i needs one of -eExX3; -i -m would rewrite input file. */
- || tag_count && ! flagging /* -L requires one of -EX. */
+ 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 ();
- if (tag_strings[0] == 0)
- tag_strings[0] = argv[optind];
- if (tag_strings[1] == 0)
- tag_strings[1] = argv[optind + 2];
+ file = &argv[optind];
- if (*argv[optind] == '-' && *(argv[optind] + 1) == '\0')
+ for (i = tag_count; i < 3; i++)
+ tag_strings[i] = file[i];
+
+ /* Always compare file1 to file2, even if file2 is "-".
+ This is needed for -mAeExX3. Using the file0 as
+ the common file would produce wrong results, because if the
+ file0-file1 diffs didn't line up with the file0-file2 diffs
+ (which is entirely possible since we don't use diff's -n option),
+ diff3 might report phantom changes from file1 to file2. */
+
+ if (strcmp (file[2], "-") == 0)
{
- /* Sigh. We've got standard input as the first arg. We can't */
- /* call diff twice on stdin */
- if (! strcmp (argv[optind + 1], "-") || ! strcmp (argv[optind + 2], "-"))
+ /* Sigh. We've got standard input as the last arg. We can't
+ call diff twice on stdin. Use the middle arg as the common
+ file instead. */
+ if (strcmp (file[0], "-") == 0 || strcmp (file[1], "-") == 0)
fatal ("`-' specified for more than one input file");
- mapping[0] = 1;
+ mapping[0] = 0;
mapping[1] = 2;
- mapping[2] = 0;
- rev_mapping[1] = 0;
- rev_mapping[2] = 1;
- rev_mapping[0] = 2;
+ mapping[2] = 1;
}
else
{
@@ -338,61 +339,71 @@ main (argc, argv)
mapping[0] = 0;
mapping[1] = 1;
mapping[2] = 2;
- rev_mapping[0] = 0;
- rev_mapping[1] = 1;
- rev_mapping[2] = 2;
}
for (i = 0; i < 3; i++)
- if (argv[optind + i][0] != '-' || argv[optind + i][1] != '\0')
- if (stat (argv[optind + i], &statb) < 0)
- perror_with_exit (argv[optind + i]);
- else if ((statb.st_mode & S_IFMT) == S_IFDIR)
+ rev_mapping[mapping[i]] = i;
+
+ for (i = 0; i < 3; i++)
+ if (strcmp (file[i], "-") != 0)
+ if (stat (file[i], &statb) < 0)
+ perror_with_exit (file[i]);
+ else if (S_ISDIR(statb.st_mode))
{
- fprintf (stderr, "%s: %s: Is a directory\n", argv0,
- argv[optind + i]);
+ fprintf (stderr, "%s: %s: Is a directory\n", argv0, file[i]);
exit (2);
}
-
- commonname = argv[optind + rev_mapping[0]];
- thread1 = process_diff (commonname, argv[optind + rev_mapping[1]]);
- thread2 = process_diff (commonname, argv[optind + rev_mapping[2]]);
- diff = make_3way_diff (thread1, thread2);
+
+ commonname = file[rev_mapping[FILEC]];
+ thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
+ if (thread1)
+ for (i = 0; i < 2; i++)
+ {
+ horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i));
+ horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i));
+ }
+ thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block);
+ diff3 = make_3way_diff (thread0, thread1);
if (edscript)
- overlaps_found
- = output_diff3_edscript (stdout, diff, mapping, rev_mapping,
- tag_strings[0], argv[optind+1], tag_strings[1]);
+ conflicts_found
+ = output_diff3_edscript (stdout, diff3, mapping, rev_mapping,
+ tag_strings[0], tag_strings[1], tag_strings[2]);
else if (merge)
{
- if (! freopen (commonname, "r", stdin))
- perror_with_exit (commonname);
- overlaps_found
- = output_diff3_merge (stdin, stdout, diff, mapping, rev_mapping,
- tag_strings[0], argv[optind+1], tag_strings[1]);
+ if (! freopen (file[rev_mapping[FILE0]], "r", stdin))
+ perror_with_exit (file[rev_mapping[FILE0]]);
+ conflicts_found
+ = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping,
+ tag_strings[0], tag_strings[1], tag_strings[2]);
if (ferror (stdin))
fatal ("read error");
}
else
{
- output_diff3 (stdout, diff, mapping, rev_mapping);
- overlaps_found = 0;
+ output_diff3 (stdout, diff3, mapping, rev_mapping);
+ conflicts_found = 0;
}
- if (ferror (stdout) || fflush (stdout) != 0)
+ if (ferror (stdout) || fclose (stdout) != 0)
fatal ("write error");
- exit (overlaps_found);
+ exit (conflicts_found);
+ return conflicts_found;
}
-
+
/*
* Explain, patiently and kindly, how to use this program. Then exit.
*/
-void
+static void
usage ()
{
- fprintf (stderr, "Usage:\t%s [-exEX3 [-i | -m] [-L label1 -L label3]] file1 file2 file3\n",
- argv0);
- fprintf (stderr, "\tOnly one of [exEX3] allowed\n");
+ fprintf (stderr, "\
+Usage: %s [options] my-file older-file your-file\n\
+Options:\n\
+ [-exAEX3v] [-i|-m] [-L label1 [-L label2 [-L label3]]] [--text] [--ed]\n\
+ [--merge] [--show-all] [--show-overlap] [--overlap-only] [--easy-only]\n\
+ [--label=label1 [--label=label2 [--label=label3]]] [--version]\n\
+ Only one of [exAEX3] is allowed\n", argv0);
exit (2);
}
@@ -400,79 +411,79 @@ usage ()
* Routines that combine the two diffs together into one. The
* algorithm used follows:
*
- * File0 is shared in common between the two diffs.
- * Diff01 is the diff between 0 and 1.
+ * File2 is shared in common between the two diffs.
* Diff02 is the diff between 0 and 2.
+ * Diff12 is the diff between 1 and 2.
*
- * 1) Find the range for the first block in File0.
- * a) Take the lowest of the two ranges (in File0) in the two
- * current blocks (one from each diff) as being the low
- * water mark. Assign the upper end of this block as
- * being the high water mark and move the current block up
- * one. Mark the block just moved over as to be used.
+ * 1) Find the range for the first block in File2.
+ * a) Take the lowest of the two ranges (in File2) in the two
+ * current blocks (one from each diff) as being the low
+ * water mark. Assign the upper end of this block as
+ * being the high water mark and move the current block up
+ * one. Mark the block just moved over as to be used.
* b) Check the next block in the diff that the high water
- * mark is *not* from.
- *
+ * mark is *not* from.
+ *
* *If* the high water mark is above
- * the low end of the range in that block,
- *
- * mark that block as to be used and move the current
- * block up. Set the high water mark to the max of
- * the high end of this block and the current. Repeat b.
- *
- * 2) Find the corresponding ranges in Files1 (from the blocks
- * in diff01; line per line outside of diffs) and in File2.
- * Create a diff3_block, reserving space as indicated by the ranges.
- *
- * 3) Copy all of the pointers for file0 in. At least for now,
- * do bcmp's between corresponding strings in the two diffs.
- *
- * 4) Copy all of the pointers for file1 and 2 in. Get what you
- * need from file0 (when there isn't a diff block, it's
- * identical to file0 within the range between diff blocks).
- *
+ * the low end of the range in that block,
+ *
+ * mark that block as to be used and move the current
+ * block up. Set the high water mark to the max of
+ * the high end of this block and the current. Repeat b.
+ *
+ * 2) Find the corresponding ranges in File0 (from the blocks
+ * in diff02; line per line outside of diffs) and in File1.
+ * Create a diff3_block, reserving space as indicated by the ranges.
+ *
+ * 3) Copy all of the pointers for file2 in. At least for now,
+ * do bcmp's between corresponding strings in the two diffs.
+ *
+ * 4) Copy all of the pointers for file0 and 1 in. Get what you
+ * need from file2 (when there isn't a diff block, it's
+ * identical to file2 within the range between diff blocks).
+ *
* 5) If the diff blocks you used came from only one of the two
- * strings of diffs, then that file (i.e. the one other than
- * file 0 in that diff) is the odd person out. If you used
- * diff blocks from both sets, check to see if files 1 and 2 match:
- *
- * Same number of lines? If so, do a set of bcmp's (if a
- * bcmp matches; copy the pointer over; it'll be easier later
- * if you have to do any compares). If they match, 1 & 2 are
- * the same. If not, all three different.
- *
- * Then you do it again, until you run out of blocks.
- *
+ * strings of diffs, then that file (i.e. the one other than
+ * the common file in that diff) is the odd person out. If you used
+ * diff blocks from both sets, check to see if files 0 and 1 match:
+ *
+ * Same number of lines? If so, do a set of bcmp's (if a
+ * bcmp matches; copy the pointer over; it'll be easier later
+ * if you have to do any compares). If they match, 0 & 1 are
+ * the same. If not, all three different.
+ *
+ * Then you do it again, until you run out of blocks.
+ *
*/
-/*
+/*
* This routine makes a three way diff (chain of diff3_block's) from two
* two way diffs (chains of diff_block's). It is assumed that each of
- * the two diffs passed are off of the same file (i.e. that each of the
- * diffs were made "from" the same file). The three way diff pointer
- * returned will have numbering 0--the common file, 1--the other file
- * in diff1, and 2--the other file in diff2.
+ * the two diffs passed are onto the same file (i.e. that each of the
+ * diffs were made "to" the same file). The three way diff pointer
+ * returned will have numbering FILE0--the other file in diff02,
+ * FILE1--the other file in diff12, and FILEC--the common file.
*/
-struct diff3_block *
-make_3way_diff (thread1, thread2)
- struct diff_block *thread1, *thread2;
+static struct diff3_block *
+make_3way_diff (thread0, thread1)
+ struct diff_block *thread0, *thread1;
{
/*
* This routine works on the two diffs passed to it as threads.
- * Thread number 0 is diff1, thread number 1 is diff2. The USING
+ * Thread number 0 is diff02, thread number 1 is diff12. The USING
* array is set to the base of the list of blocks to be used to
* construct each block of the three way diff; if no blocks from a
* particular thread are to be used, that element of the using array
* is set to 0. The elements LAST_USING array are set to the last
* elements on each of the using lists.
*
- * The HIGH_WATER_MARK is set to the highest line number in File 0
+ * The HIGH_WATER_MARK is set to the highest line number in the common file
* described in any of the diffs in either of the USING lists. The
* HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK
- * and BASE_WATER_THREAD describe the lowest line number in File 0
+ * and BASE_WATER_THREAD describe the lowest line number in the common file
* described in any of the diffs in either of the USING lists. The
* HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
- * taken.
+ * taken.
*
* The HIGH_WATER_DIFF should always be equal to LAST_USING
* [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for
@@ -507,10 +518,10 @@ make_3way_diff (thread1, thread2)
struct diff3_block
*result,
*tmpblock,
- *result_last,
- *last_diff;
+ **result_end,
+ *last_diff3;
- static struct diff3_block zero_diff = {
+ static struct diff3_block zero_diff3 = {
ERROR,
{ {0, 0}, {0, 0}, {0, 0} },
{ (char **) 0, (char **) 0, (char **) 0 },
@@ -519,9 +530,10 @@ make_3way_diff (thread1, thread2)
};
/* Initialization */
- result = result_last = (struct diff3_block *) 0;
- current[0] = thread1; current[1] = thread2;
- last_diff = &zero_diff;
+ result = 0;
+ result_end = &result;
+ current[0] = thread0; current[1] = thread1;
+ last_diff3 = &zero_diff3;
/* Sniff up the threads until we reach the end */
@@ -537,18 +549,18 @@ make_3way_diff (thread1, thread2)
base_water_thread = 0;
else
base_water_thread =
- (D_LOWLINE (current[0], FILE0) > D_LOWLINE (current[1], FILE0));
+ (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
high_water_thread = base_water_thread;
-
+
high_water_diff = current[high_water_thread];
-
+
#if 0
/* low and high waters start off same diff */
- base_water_mark = D_LOWLINE (high_water_diff, FILE0);
+ base_water_mark = D_LOWLINE (high_water_diff, FC);
#endif
- high_water_mark = D_HIGHLINE (high_water_diff, FILE0);
+ high_water_mark = D_HIGHLINE (high_water_diff, FC);
/* Make the diff you just got info from into the using class */
using[high_water_thread]
@@ -563,9 +575,9 @@ make_3way_diff (thread1, thread2)
other_diff = current[other_thread];
/* Shuffle up the ladder, checking the other diff to see if it
- needs to be incorporated */
+ needs to be incorporated. */
while (other_diff
- && D_LOWLINE (other_diff, FILE0) <= high_water_mark + 1)
+ && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
{
/* Incorporate this diff into the using list. Note that
@@ -588,13 +600,13 @@ make_3way_diff (thread1, thread2)
If this comparison is equal, then this is the last pass
through this loop; since diff blocks within a given
thread cannot overlap, the high_water_mark will be
- *below* the range_start of either of the next diffs. */
+ *below* the range_start of either of the next diffs. */
- if (high_water_mark < D_HIGHLINE (other_diff, FILE0))
+ if (high_water_mark < D_HIGHLINE (other_diff, FC))
{
high_water_thread ^= 1;
high_water_diff = other_diff;
- high_water_mark = D_HIGHLINE (other_diff, FILE0);
+ high_water_mark = D_HIGHLINE (other_diff, FC);
}
/* Set the other diff */
@@ -603,24 +615,21 @@ make_3way_diff (thread1, thread2)
}
/* The using lists contain a list of all of the blocks to be
- included in this diff3_block. Create it. */
+ included in this diff3_block. Create it. */
tmpblock = using_to_diff3_block (using, last_using,
base_water_thread, high_water_thread,
- last_diff);
+ last_diff3);
if (!tmpblock)
- fatal ("internal: screwup in format of diff blocks");
+ fatal ("internal error: screwup in format of diff blocks");
- /* Put it on the list */
- if (result)
- result_last->next = tmpblock;
- else
- result = tmpblock;
- result_last = tmpblock;
+ /* Put it on the list. */
+ *result_end = tmpblock;
+ result_end = &tmpblock->next;
- /* Setup corresponding lines correctly */
- last_diff = tmpblock;
+ /* Set up corresponding lines correctly. */
+ last_diff3 = tmpblock;
}
return result;
}
@@ -637,7 +646,7 @@ make_3way_diff (thread1, thread2)
* structure.
* LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
* and highest line numbers for File0.
- * last_diff contains the last diff produced in the calling routine.
+ * last_diff3 contains the last diff produced in the calling routine.
* This is used for lines mappings which would still be identical to
* the state that diff ended in.
*
@@ -645,188 +654,120 @@ make_3way_diff (thread1, thread2)
* that are part of a normal two diff block, and the three diffs that
* are part of a diff3_block.
*/
-struct diff3_block *
-using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff)
+static struct diff3_block *
+using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3)
struct diff_block
*using[2],
*last_using[2];
int low_thread, high_thread;
- struct diff3_block *last_diff;
+ struct diff3_block *last_diff3;
{
- int lowc, highc, low1, high1, low2, high2;
+ int low[2], high[2];
struct diff3_block *result;
struct diff_block *ptr;
- int i;
- int current0line;
-
- /* Find the range in file0 */
- lowc = using[low_thread]->ranges[0][START];
- highc = last_using[high_thread]->ranges[0][END];
+ int d, i;
- /* Find the ranges in the other files.
- If using[x] is null, that means that the file to which that diff
- refers is equivalent to file 0 over this range */
-
- if (using[0])
- {
- low1 = D_LOW_MAPLINE (using[0], FILE0, FILE1, lowc);
- high1 = D_HIGH_MAPLINE (last_using[0], FILE0, FILE1, highc);
- }
- else
- {
- low1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, lowc);
- high1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, highc);
- }
+ /* Find the range in the common file. */
+ int lowc = D_LOWLINE (using[low_thread], FC);
+ int highc = D_HIGHLINE (last_using[high_thread], FC);
- /*
- * Note that in the following, we use file 1 relative to the diff,
- * and file 2 relative to the corresponding lines struct.
- */
- if (using[1])
- {
- low2 = D_LOW_MAPLINE (using[1], FILE0, FILE1, lowc);
- high2 = D_HIGH_MAPLINE (last_using[1], FILE0, FILE1, highc);
- }
- else
- {
- low2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, lowc);
- high2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, highc);
- }
+ /* Find the ranges in the other files.
+ If using[d] is null, that means that the file to which that diff
+ refers is equivalent to the common file over this range. */
+
+ for (d = 0; d < 2; d++)
+ if (using[d])
+ {
+ low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
+ high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
+ }
+ else
+ {
+ low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
+ high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
+ }
/* Create a block with the appropriate sizes */
- result = create_diff3_block (lowc, highc, low1, high1, low2, high2);
+ result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
- /* Copy over all of the information for File 0. Return with a zero
- if any of the compares failed. */
- for (ptr = using[0]; ptr; ptr = D_NEXT (ptr))
- {
- int result_offset = D_LOWLINE (ptr, FILE0) - lowc;
- int copy_size
- = D_HIGHLINE (ptr, FILE0) - D_LOWLINE (ptr, FILE0) + 1;
-
- if (!copy_stringlist (D_LINEARRAY (ptr, FILE0),
- D_LENARRAY (ptr, FILE0),
- D_LINEARRAY (result, FILEC) + result_offset,
- D_LENARRAY (result, FILEC) + result_offset,
- copy_size))
- return 0;
- }
+ /* Copy information for the common file.
+ Return with a zero if any of the compares failed. */
- for (ptr = using[1]; ptr; ptr = D_NEXT (ptr))
- {
- int result_offset = D_LOWLINE (ptr, FILEC) - lowc;
- int copy_size
- = D_HIGHLINE (ptr, FILEC) - D_LOWLINE (ptr, FILEC) + 1;
-
- if (!copy_stringlist (D_LINEARRAY (ptr, FILE0),
- D_LENARRAY (ptr, FILE0),
- D_LINEARRAY (result, FILEC) + result_offset,
- D_LENARRAY (result, FILEC) + result_offset,
- copy_size))
- return 0;
- }
+ for (d = 0; d < 2; d++)
+ for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
+ {
+ int result_offset = D_LOWLINE (ptr, FC) - lowc;
- /* Copy stuff for file 1. First deal with anything that might be
- before the first diff. */
+ if (!copy_stringlist (D_LINEARRAY (ptr, FC),
+ D_LENARRAY (ptr, FC),
+ D_LINEARRAY (result, FILEC) + result_offset,
+ D_LENARRAY (result, FILEC) + result_offset,
+ D_NUMLINES (ptr, FC)))
+ return 0;
+ }
- for (i = 0;
- i + low1 < (using[0] ? D_LOWLINE (using[0], FILE1) : high1 + 1);
- i++)
- {
- D_RELNUM (result, FILE1, i) = D_RELNUM (result, FILEC, i);
- D_RELLEN (result, FILE1, i) = D_RELLEN (result, FILEC, i);
- }
-
- for (ptr = using[0]; ptr; ptr = D_NEXT (ptr))
+ /* Copy information for file d. First deal with anything that might be
+ before the first diff. */
+
+ for (d = 0; d < 2; d++)
{
- int result_offset = D_LOWLINE (ptr, FILE1) - low1;
- int copy_size
- = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1;
-
- if (!copy_stringlist (D_LINEARRAY (ptr, FILE1),
- D_LENARRAY (ptr, FILE1),
- D_LINEARRAY (result, FILE1) + result_offset,
- D_LENARRAY (result, FILE1) + result_offset,
- copy_size))
- return 0;
-
- /* Catch the lines between here and the next diff */
- current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc;
- for (i = D_HIGHLINE (ptr, FILE1) + 1 - low1;
- i < (D_NEXT (ptr) ?
- D_LOWLINE (D_NEXT (ptr), FILE1) :
- high1 + 1) - low1;
+ struct diff_block *u = using[d];
+ int lo = low[d], hi = high[d];
+
+ for (i = 0;
+ i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
i++)
{
- D_RELNUM (result, FILE1, i)
- = D_RELNUM (result, FILEC, current0line);
- D_RELLEN (result, FILE1, i)
- = D_RELLEN (result, FILEC, current0line++);
+ D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
+ D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
}
- }
- /* Copy stuff for file 2. First deal with anything that might be
- before the first diff. */
-
- for (i = 0;
- i + low2 < (using[1] ? D_LOWLINE (using[1], FILE1) : high2 + 1);
- i++)
- {
- D_RELNUM (result, FILE2, i) = D_RELNUM (result, FILEC, i);
- D_RELLEN (result, FILE2, i) = D_RELLEN (result, FILEC, i);
- }
-
- for (ptr = using[1]; ptr; ptr = D_NEXT (ptr))
- {
- int result_offset = D_LOWLINE (ptr, FILE1) - low2;
- int copy_size
- = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1;
-
- if (!copy_stringlist (D_LINEARRAY (ptr, FILE1),
- D_LENARRAY (ptr, FILE1),
- D_LINEARRAY (result, FILE2) + result_offset,
- D_LENARRAY (result, FILE2) + result_offset,
- copy_size))
- return 0;
-
- /* Catch the lines between here and the next diff */
- current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc;
- for (i = D_HIGHLINE (ptr, FILE1) + 1 - low2;
- i < (D_NEXT (ptr) ?
- D_LOWLINE (D_NEXT (ptr), FILE1) :
- high2 + 1) - low2;
- i++)
+ for (ptr = u; ptr; ptr = D_NEXT (ptr))
{
- D_RELNUM (result, FILE2, i)
- = D_RELNUM (result, FILEC, current0line);
- D_RELLEN (result, FILE2, i)
- = D_RELLEN (result, FILEC, current0line++);
+ int result_offset = D_LOWLINE (ptr, FO) - lo;
+ int linec;
+
+ if (!copy_stringlist (D_LINEARRAY (ptr, FO),
+ D_LENARRAY (ptr, FO),
+ D_LINEARRAY (result, FILE0 + d) + result_offset,
+ D_LENARRAY (result, FILE0 + d) + result_offset,
+ D_NUMLINES (ptr, FO)))
+ return 0;
+
+ /* Catch the lines between here and the next diff */
+ linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
+ for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
+ i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
+ i++)
+ {
+ D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
+ D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
+ linec++;
+ }
}
}
/* Set correspond */
if (!using[0])
- D3_TYPE (result) = DIFF_3RD;
- else if (!using[1])
D3_TYPE (result) = DIFF_2ND;
+ else if (!using[1])
+ D3_TYPE (result) = DIFF_1ST;
else
{
- int nl1
- = D_HIGHLINE (result, FILE1) - D_LOWLINE (result, FILE1) + 1;
- int nl2
- = D_HIGHLINE (result, FILE2) - D_LOWLINE (result, FILE2) + 1;
+ int nl0 = D_NUMLINES (result, FILE0);
+ int nl1 = D_NUMLINES (result, FILE1);
- if (nl1 != nl2
- || !compare_line_list (D_LINEARRAY (result, FILE1),
+ if (nl0 != nl1
+ || !compare_line_list (D_LINEARRAY (result, FILE0),
+ D_LENARRAY (result, FILE0),
+ D_LINEARRAY (result, FILE1),
D_LENARRAY (result, FILE1),
- D_LINEARRAY (result, FILE2),
- D_LENARRAY (result, FILE2),
- nl1))
+ nl0))
D3_TYPE (result) = DIFF_ALL;
else
- D3_TYPE (result) = DIFF_1ST;
+ D3_TYPE (result) = DIFF_3RD;
}
-
+
return result;
}
@@ -837,7 +778,7 @@ using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff)
* returns 0, the copy incomplete.
* Upon successful completion of the copy, it returns 1.
*/
-int
+static int
copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
char *fromptrs[], *toptrs[];
int *fromlengths, *tolengths;
@@ -849,7 +790,7 @@ copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
register int
*fl = fromlengths,
*tl = tolengths;
-
+
while (copynum--)
{
if (*t)
@@ -867,7 +808,7 @@ copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
* Allocate the arrays for the various pointers (and zero them) based
* on the arguments passed. Return the block as a result.
*/
-struct diff3_block *
+static struct diff3_block *
create_diff3_block (low0, high0, low1, high1, low2, high2)
register int low0, high0, low1, high1, low2, high2;
{
@@ -936,7 +877,7 @@ create_diff3_block (low0, high0, low1, high1, low2, high2)
* Compare two lists of lines of text.
* Return 1 if they are equivalent, 0 if not.
*/
-int
+static int
compare_line_list (list1, lengths1, list2, lengths2, nl)
char *list1[], *list2[];
int *lengths1, *lengths2;
@@ -948,7 +889,7 @@ compare_line_list (list1, lengths1, list2, lengths2, nl)
int
*lgths1 = lengths1,
*lgths2 = lengths2;
-
+
while (nl--)
if (!*l1 || !*l2 || *lgths1 != *lgths2++
|| bcmp (*l1++, *l2++, *lgths1++))
@@ -956,7 +897,7 @@ compare_line_list (list1, lengths1, list2, lengths2, nl)
return 1;
}
-/*
+/*
* Routines to input and parse two way diffs.
*/
@@ -964,28 +905,28 @@ extern char **environ;
#define DIFF_CHUNK_SIZE 10000
-struct diff_block *
-process_diff (filea, fileb)
+static struct diff_block *
+process_diff (filea, fileb, last_block)
char *filea, *fileb;
+ struct diff_block **last_block;
{
char *diff_contents;
char *diff_limit;
char *scan_diff;
enum diff_type dt;
int i;
- struct diff_block *block_list, *block_list_end, *bptr;
+ struct diff_block *block_list, **block_list_end, *bptr;
diff_limit = read_diff (filea, fileb, &diff_contents);
scan_diff = diff_contents;
- bptr = block_list_end = block_list = (struct diff_block *) 0;
+ block_list_end = &block_list;
while (scan_diff < diff_limit)
{
bptr = ALLOCATE (1, struct diff_block);
- bptr->next = 0;
bptr->lines[0] = bptr->lines[1] = (char **) 0;
bptr->lengths[0] = bptr->lengths[1] = (int *) 0;
-
+
dt = process_diff_control (&scan_diff, bptr);
if (dt == ERROR || *scan_diff != '\n')
{
@@ -998,7 +939,7 @@ process_diff (filea, fileb)
exit (2);
}
scan_diff++;
-
+
/* Force appropriate ranges to be null, if necessary */
switch (dt)
{
@@ -1011,66 +952,55 @@ process_diff (filea, fileb)
case CHANGE:
break;
default:
- fatal ("internal: Bad diff type in process_diff");
+ fatal ("internal error: invalid diff type in process_diff");
break;
}
-
+
/* Allocate space for the pointers for the lines from filea, and
parcel them out among these pointers */
if (dt != ADD)
{
- bptr->lines[0] = ALLOCATE ((bptr->ranges[0][END]
- - bptr->ranges[0][START] + 1),
- char *);
- bptr->lengths[0] = ALLOCATE ((bptr->ranges[0][END]
- - bptr->ranges[0][START] + 1),
- int);
- for (i = 0; i <= (bptr->ranges[0][END]
- - bptr->ranges[0][START]); i++)
+ int numlines = D_NUMLINES (bptr, 0);
+ bptr->lines[0] = ALLOCATE (numlines, char *);
+ bptr->lengths[0] = ALLOCATE (numlines, int);
+ for (i = 0; i < numlines; i++)
scan_diff = scan_diff_line (scan_diff,
&(bptr->lines[0][i]),
&(bptr->lengths[0][i]),
diff_limit,
'<');
}
-
+
/* Get past the separator for changes */
if (dt == CHANGE)
{
if (strncmp (scan_diff, "---\n", 4))
- fatal ("Bad diff format: bad change separator");
+ fatal ("invalid diff format; invalid change separator");
scan_diff += 4;
}
-
+
/* Allocate space for the pointers for the lines from fileb, and
parcel them out among these pointers */
if (dt != DELETE)
{
- bptr->lines[1] = ALLOCATE ((bptr->ranges[1][END]
- - bptr->ranges[1][START] + 1),
- char *);
- bptr->lengths[1] = ALLOCATE ((bptr->ranges[1][END]
- - bptr->ranges[1][START] + 1),
- int);
- for (i = 0; i <= (bptr->ranges[1][END]
- - bptr->ranges[1][START]); i++)
+ int numlines = D_NUMLINES (bptr, 1);
+ bptr->lines[1] = ALLOCATE (numlines, char *);
+ bptr->lengths[1] = ALLOCATE (numlines, int);
+ for (i = 0; i < numlines; i++)
scan_diff = scan_diff_line (scan_diff,
&(bptr->lines[1][i]),
&(bptr->lengths[1][i]),
diff_limit,
'>');
}
-
- /* Place this block on the blocklist */
- if (block_list_end)
- block_list_end->next = bptr;
- else
- block_list = bptr;
-
- block_list_end = bptr;
-
+
+ /* Place this block on the blocklist. */
+ *block_list_end = bptr;
+ block_list_end = &bptr->next;
}
+ *block_list_end = 0;
+ *last_block = bptr;
return block_list;
}
@@ -1087,10 +1017,10 @@ process_diff (filea, fileb)
* number, then both corresponding numbers in the diff block are set
* to that number. In general these numbers are interpetted as ranges
* inclusive, unless being used by the ADD or DELETE commands. It is
- * assumed that these will be special cased in a superior routine.
+ * assumed that these will be special cased in a superior routine.
*/
-enum diff_type
+static enum diff_type
process_diff_control (string, db)
char **string;
struct diff_block *db;
@@ -1117,7 +1047,7 @@ process_diff_control (string, db)
READNUM (s, db->ranges[0][START]);
/* Was that the only digit? */
- SKIPWHITE(s);
+ SKIPWHITE (s);
if (*s == ',')
{
/* Get the next digit */
@@ -1144,13 +1074,13 @@ process_diff_control (string, db)
return ERROR; /* Bad format */
}
s++; /* Past letter */
-
+
/* Read second set of digits */
SKIPWHITE (s);
READNUM (s, db->ranges[1][START]);
/* Was that the only digit? */
- SKIPWHITE(s);
+ SKIPWHITE (s);
if (*s == ',')
{
/* Get the next digit */
@@ -1165,12 +1095,13 @@ process_diff_control (string, db)
return type;
}
-char *
+static char *
read_diff (filea, fileb, output_placement)
char *filea, *fileb;
char **output_placement;
{
- char *argv[6];
+ char *argv[7];
+ char horizon_arg[256];
char **ap;
int fds[2];
char *diff_result;
@@ -1184,13 +1115,15 @@ read_diff (filea, fileb, output_placement)
*ap++ = diff_program;
if (always_text)
*ap++ = "-a";
+ sprintf (horizon_arg, "--horizon-lines=%d", horizon_lines);
+ *ap++ = horizon_arg;
*ap++ = "--";
*ap++ = filea;
*ap++ = fileb;
*ap = (char *) 0;
if (pipe (fds) < 0)
- perror_with_exit ("Pipe failed");
+ perror_with_exit ("pipe failed");
pid = vfork ();
if (pid == 0)
@@ -1203,14 +1136,14 @@ read_diff (filea, fileb, output_placement)
close (fds[1]);
}
execve (diff_program, argv, environ);
- /* Avoid stdio, because the parent process's buffers are inherited. */
+ /* Avoid stdio, because the parent process's buffers are inherited. */
write (fileno (stderr), diff_program, strlen (diff_program));
write (fileno (stderr), ": not found\n", 12);
_exit (2);
}
if (pid == -1)
- perror_with_exit ("Fork failed");
+ perror_with_exit ("fork failed");
close (fds[1]); /* Prevent erroneous lack of EOF */
current_chunk_size = DIFF_CHUNK_SIZE;
@@ -1226,17 +1159,17 @@ read_diff (filea, fileb, output_placement)
} while (bytes);
if (total != 0 && diff_result[total-1] != '\n')
- fatal ("bad diff format; incomplete last line");
+ fatal ("invalid diff format; incomplete last line");
*output_placement = diff_result;
do
if ((w = wait (&wstatus)) == -1)
- perror_with_exit ("Wait failed");
+ perror_with_exit ("wait failed");
while (w != pid);
if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
- fatal ("Subsidiary diff failed");
+ fatal ("subsidiary diff failed");
return diff_result + total;
}
@@ -1249,7 +1182,7 @@ read_diff (filea, fileb, output_placement)
* This next routine began life as a macro and many parameters in it
* are used as call-by-reference values.
*/
-char *
+static char *
scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar)
char *scan_ptr, **set_start;
int *set_length;
@@ -1260,7 +1193,7 @@ scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar)
if (!(scan_ptr[0] == (firstchar)
&& scan_ptr[1] == ' '))
- fatal ("Bad diff format; incorrect leading line chars");
+ fatal ("invalid diff format; incorrect leading line chars");
*set_start = line_ptr = scan_ptr + 2;
while (*line_ptr++ != '\n')
@@ -1297,11 +1230,11 @@ scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar)
* argument list) and contains the internal file number (from the
* diff passed). This is important because the user expects his
* outputs in terms of the argument list number, and the diff passed
- * may have been done slightly differently (if the first argument in
- * the argument list was the standard input, for example).
+ * may have been done slightly differently (if the last argument
+ * was "-", for example).
* REV_MAPPING is the inverse of MAPPING.
*/
-void
+static void
output_diff3 (outputfile, diff, mapping, rev_mapping)
FILE *outputfile;
struct diff3_block *diff;
@@ -1331,17 +1264,17 @@ output_diff3 (outputfile, diff, mapping, rev_mapping)
case DIFF_2ND:
case DIFF_3RD:
oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST];
-
+
x[0] = oddoneout + '1';
x[1] = '\0';
dontprint = oddoneout==0;
break;
default:
- fatal ("internal: Bad diff type passed to output");
+ fatal ("internal error: invalid diff type passed to output");
}
fprintf (outputfile, "====%s\n", x);
- /* Go 0, 2, 1 if the first and third outputs are equivalent. */
+ /* Go 0, 2, 1 if the first and third outputs are equivalent. */
for (i = 0; i < 3;
i = (oddoneout == 1 ? skew_increment[i] : i + 1))
{
@@ -1349,7 +1282,7 @@ output_diff3 (outputfile, diff, mapping, rev_mapping)
int
lowt = D_LOWLINE (ptr, realfile),
hight = D_HIGHLINE (ptr, realfile);
-
+
fprintf (outputfile, "%d:", i + 1);
switch (lowt - hight)
{
@@ -1379,6 +1312,55 @@ output_diff3 (outputfile, diff, mapping, rev_mapping)
}
}
+
+/*
+ * Output to OUTPUTFILE the lines of B taken from FILENUM.
+ * Double any initial '.'s; yield nonzero if any initial '.'s were doubled.
+ */
+static int
+dotlines (outputfile, b, filenum)
+ FILE *outputfile;
+ struct diff3_block *b;
+ int filenum;
+{
+ int i;
+ int leading_dot = 0;
+
+ for (i = 0;
+ i < D_NUMLINES (b, filenum);
+ i++)
+ {
+ char *line = D_RELNUM (b, filenum, i);
+ if (line[0] == '.')
+ {
+ leading_dot = 1;
+ fprintf (outputfile, ".");
+ }
+ fwrite (line, sizeof (char),
+ D_RELLEN (b, filenum, i), outputfile);
+ }
+
+ return leading_dot;
+}
+
+/*
+ * Output to OUTPUTFILE a '.' line. If LEADING_DOT is nonzero,
+ * also output a command that removes initial '.'s
+ * starting with line START and continuing for NUM lines.
+ */
+static void
+undotlines (outputfile, leading_dot, start, num)
+ FILE *outputfile;
+ int leading_dot, start, num;
+{
+ fprintf (outputfile, ".\n");
+ if (leading_dot)
+ if (num == 1)
+ fprintf (outputfile, "%ds/^\\.//\n", start);
+ else
+ fprintf (outputfile, "%d,%ds/^\\.//\n", start, start + num - 1);
+}
+
/*
* This routine outputs a diff3 set of blocks as an ed script. This
* script applies the changes between file's 2 & 3 to file 1. It
@@ -1398,10 +1380,10 @@ output_diff3 (outputfile, diff, mapping, rev_mapping)
* as the names of the three files. These may be the actual names,
* or may be the arguments specified with -L.
*
- * Returns 1 if overlaps were found.
+ * Returns 1 if conflicts were found.
*/
-int
+static int
output_diff3_edscript (outputfile, diff, mapping, rev_mapping,
file0, file1, file2)
FILE *outputfile;
@@ -1409,124 +1391,115 @@ output_diff3_edscript (outputfile, diff, mapping, rev_mapping,
int mapping[3], rev_mapping[3];
char *file0, *file1, *file2;
{
- int i;
int leading_dot;
- int overlaps_found = 0;
- struct diff3_block *newblock, *thisblock;
-
- leading_dot = 0;
-
- newblock = reverse_diff3_blocklist (diff);
+ int conflicts_found = 0, conflict;
+ struct diff3_block *b;
- for (thisblock = newblock; thisblock; thisblock = thisblock->next)
+ for (b = reverse_diff3_blocklist (diff); b; b = b->next)
{
/* Must do mapping correctly. */
enum diff_type type
- = ((thisblock->correspond == DIFF_ALL) ?
+ = ((b->correspond == DIFF_ALL) ?
DIFF_ALL :
((enum diff_type)
(((int) DIFF_1ST)
- + rev_mapping[(int) thisblock->correspond - (int) DIFF_1ST])));
+ + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
- /* If we aren't supposed to do this output block, skip it */
- if (type == DIFF_2ND || type == DIFF_1ST
- || (type == DIFF_3RD && dont_write_simple)
- || (type == DIFF_ALL && dont_write_overlap))
- continue;
+ /* If we aren't supposed to do this output block, skip it. */
+ switch (type)
+ {
+ default: continue;
+ case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
+ case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
+ case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
+ }
- if (flagging && type == DIFF_ALL)
- /* Do special flagging */
+ if (conflict)
{
+ conflicts_found = 1;
- /* Put in lines from FILE2 with bracket */
- fprintf (outputfile, "%da\n",
- D_HIGHLINE (thisblock, mapping[FILE0]));
- fprintf (outputfile, "=======\n");
- for (i = 0;
- i < D_NUMLINES (thisblock, mapping[FILE2]);
- i++)
+
+ /* Mark end of conflict. */
+
+ fprintf (outputfile, "%da\n", D_HIGHLINE (b, mapping[FILE0]));
+ leading_dot = 0;
+ if (type == DIFF_ALL)
{
- if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.')
- { leading_dot = 1; fprintf(outputfile, "."); }
- fwrite (D_RELNUM (thisblock, mapping[FILE2], i), sizeof (char),
- D_RELLEN (thisblock, mapping[FILE2], i), outputfile);
+ if (show_2nd)
+ {
+ /* Append lines from FILE1. */
+ fprintf (outputfile, "||||||| %s\n", file1);
+ leading_dot = dotlines (outputfile, b, mapping[FILE1]);
+ }
+ /* Append lines from FILE2. */
+ fprintf (outputfile, "=======\n");
+ leading_dot |= dotlines (outputfile, b, mapping[FILE2]);
}
- fprintf (outputfile, ">>>>>>> %s\n.\n", file2);
- overlaps_found = 1;
+ fprintf (outputfile, ">>>>>>> %s\n", file2);
+ undotlines (outputfile, leading_dot,
+ D_HIGHLINE (b, mapping[FILE0]) + 2,
+ (D_NUMLINES (b, mapping[FILE1])
+ + D_NUMLINES (b, mapping[FILE2]) + 1));
+
- /* Add in code to take care of leading dots, if necessary. */
- if (leading_dot)
+ /* Mark start of conflict. */
+
+ fprintf (outputfile, "%da\n<<<<<<< %s\n",
+ D_LOWLINE (b, mapping[FILE0]) - 1,
+ type == DIFF_ALL ? file0 : file1);
+ leading_dot = 0;
+ if (type == DIFF_2ND)
{
- fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n",
- D_HIGHLINE (thisblock, mapping[FILE0]) + 1,
- (D_HIGHLINE (thisblock, mapping[FILE0])
- + D_NUMLINES (thisblock, mapping[FILE2])));
- leading_dot = 0;
+ /* Prepend lines from FILE1. */
+ leading_dot = dotlines (outputfile, b, mapping[FILE1]);
+ fprintf (outputfile, "=======\n");
}
-
- /* Put in code to do initial bracket of lines from FILE0 */
- fprintf (outputfile, "%da\n<<<<<<< %s\n.\n",
- D_LOWLINE (thisblock, mapping[FILE0]) - 1,
- file0);
+ undotlines (outputfile, leading_dot,
+ D_LOWLINE (b, mapping[FILE0]) + 1,
+ D_NUMLINES (b, mapping[FILE1]));
}
- else if (D_NUMLINES (thisblock, mapping[FILE2]) == 0)
+ else if (D_NUMLINES (b, mapping[FILE2]) == 0)
/* Write out a delete */
{
- if (D_NUMLINES (thisblock, mapping[FILE0]) == 1)
+ if (D_NUMLINES (b, mapping[FILE0]) == 1)
fprintf (outputfile, "%dd\n",
- D_LOWLINE (thisblock, mapping[FILE0]));
+ D_LOWLINE (b, mapping[FILE0]));
else
fprintf (outputfile, "%d,%dd\n",
- D_LOWLINE (thisblock, mapping[FILE0]),
- D_HIGHLINE (thisblock, mapping[FILE0]));
+ D_LOWLINE (b, mapping[FILE0]),
+ D_HIGHLINE (b, mapping[FILE0]));
}
else
/* Write out an add or change */
{
- switch (D_NUMLINES (thisblock, mapping[FILE0]))
+ switch (D_NUMLINES (b, mapping[FILE0]))
{
case 0:
fprintf (outputfile, "%da\n",
- D_HIGHLINE (thisblock, mapping[FILE0]));
+ D_HIGHLINE (b, mapping[FILE0]));
break;
case 1:
fprintf (outputfile, "%dc\n",
- D_HIGHLINE (thisblock, mapping[FILE0]));
+ D_HIGHLINE (b, mapping[FILE0]));
break;
default:
fprintf (outputfile, "%d,%dc\n",
- D_LOWLINE (thisblock, mapping[FILE0]),
- D_HIGHLINE (thisblock, mapping[FILE0]));
+ D_LOWLINE (b, mapping[FILE0]),
+ D_HIGHLINE (b, mapping[FILE0]));
break;
}
- for (i = 0;
- i < D_NUMLINES (thisblock, mapping[FILE2]);
- i++)
- {
- if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.')
- { leading_dot = 1; fprintf (outputfile, "."); }
- fwrite (D_RELNUM (thisblock, mapping[FILE2], i), sizeof (char),
- D_RELLEN (thisblock, mapping[FILE2], i), outputfile);
- }
- fprintf (outputfile, ".\n");
-
- /* Add in code to take care of leading dots, if necessary. */
- if (leading_dot)
- {
- fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n",
- D_HIGHLINE (thisblock, mapping[FILE0]) + 1,
- (D_HIGHLINE (thisblock, mapping[FILE0])
- + D_NUMLINES (thisblock, mapping[FILE2])));
- leading_dot = 0;
- }
+
+ undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]),
+ D_LOWLINE (b, mapping[FILE0]),
+ D_NUMLINES (b, mapping[FILE2]));
}
}
if (finalwrite) fprintf (outputfile, "w\nq\n");
- return overlaps_found;
+ return conflicts_found;
}
/*
- * Read from COMMONFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF
+ * Read from INFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF
* as a merged file. This acts like 'ed file0 <[output_diff3_edscript]',
* except that it works even for binary data or incomplete lines.
*
@@ -1534,64 +1507,87 @@ output_diff3_edscript (outputfile, diff, mapping, rev_mapping,
* REV_MAPPING is its inverse,
* and FILE0, FILE1, and FILE2 are the names of the files.
*
- * Returns 1 if overlaps were found.
+ * Returns 1 if conflicts were found.
*/
-int
-output_diff3_merge (commonfile, outputfile, diff, mapping, rev_mapping,
+static int
+output_diff3_merge (infile, outputfile, diff, mapping, rev_mapping,
file0, file1, file2)
- FILE *commonfile, *outputfile;
+ FILE *infile, *outputfile;
struct diff3_block *diff;
int mapping[3], rev_mapping[3];
char *file0, *file1, *file2;
{
int c, i;
- int overlaps_found = 0;
+ int conflicts_found = 0, conflict;
struct diff3_block *b;
int linesread = 0;
for (b = diff; b; b = b->next)
{
- /* Must do mapping correctly */
+ /* Must do mapping correctly. */
enum diff_type type
= ((b->correspond == DIFF_ALL) ?
DIFF_ALL :
((enum diff_type)
(((int) DIFF_1ST)
+ rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
+ char *format_2nd = "<<<<<<< %s\n";
/* If we aren't supposed to do this output block, skip it. */
- if (type == DIFF_2ND || type == DIFF_1ST
- || (type == DIFF_3RD && dont_write_simple)
- || (type == DIFF_ALL && dont_write_overlap))
- continue;
+ switch (type)
+ {
+ default: continue;
+ case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
+ case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
+ case DIFF_ALL: if (simple_only) continue; conflict = flagging;
+ format_2nd = "||||||| %s\n";
+ break;
+ }
- /* Copy I lines from common file. */
+ /* Copy I lines from file 0. */
i = D_LOWLINE (b, FILE0) - linesread - 1;
linesread += i;
while (0 <= --i)
+ do
+ {
+ c = getc (infile);
+ if (c == EOF)
+ if (ferror (infile))
+ perror_with_exit ("input file");
+ else if (feof (infile))
+ fatal ("input file shrank");
+ putc (c, outputfile);
+ }
+ while (c != '\n');
+
+ if (conflict)
{
- while ((c = getc(commonfile)) != '\n')
+ conflicts_found = 1;
+
+ if (type == DIFF_ALL)
{
- if (c == EOF)
- fatal ("input file shrank");
- putc (c, outputfile);
+ /* Put in lines from FILE0 with bracket. */
+ fprintf (outputfile, "<<<<<<< %s\n", file0);
+ for (i = 0;
+ i < D_NUMLINES (b, mapping[FILE0]);
+ i++)
+ fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
+ D_RELLEN (b, mapping[FILE0], i), outputfile);
+ }
+
+ if (show_2nd)
+ {
+ /* Put in lines from FILE1 with bracket. */
+ fprintf (outputfile, format_2nd, file1);
+ for (i = 0;
+ i < D_NUMLINES (b, mapping[FILE1]);
+ i++)
+ fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char),
+ D_RELLEN (b, mapping[FILE1], i), outputfile);
}
- putc (c, outputfile);
- }
- if (flagging && type == DIFF_ALL)
- /* Do special flagging. */
- {
- /* Put in lines from FILE0 with bracket. */
- fprintf (outputfile, "<<<<<<< %s\n", file0);
- for (i = 0;
- i < D_NUMLINES (b, mapping[FILE0]);
- i++)
- fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
- D_RELLEN (b, mapping[FILE0], i), outputfile);
fprintf (outputfile, "=======\n");
- overlaps_found = 1;
}
/* Put in lines from FILE2. */
@@ -1601,31 +1597,34 @@ output_diff3_merge (commonfile, outputfile, diff, mapping, rev_mapping,
fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
D_RELLEN (b, mapping[FILE2], i), outputfile);
- if (flagging && type == DIFF_ALL)
+ if (conflict)
fprintf (outputfile, ">>>>>>> %s\n", file2);
- /* Skip I lines in common file. */
+ /* Skip I lines in file 0. */
i = D_NUMLINES (b, FILE0);
linesread += i;
while (0 <= --i)
- while ((c = getc(commonfile)) != '\n')
+ while ((c = getc (infile)) != '\n')
if (c == EOF)
- {
- if (i || b->next)
- fatal ("input file shrank");
- return overlaps_found;
- }
+ if (ferror (infile))
+ perror_with_exit ("input file");
+ else if (feof (infile))
+ {
+ if (i || b->next)
+ fatal ("input file shrank");
+ return conflicts_found;
+ }
}
/* Copy rest of common file. */
- while ((c = getc (commonfile)) != EOF)
+ while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
putc (c, outputfile);
- return overlaps_found;
+ return conflicts_found;
}
/*
* Reverse the order of the list of diff3 blocks.
*/
-struct diff3_block *
+static struct diff3_block *
reverse_diff3_blocklist (diff)
struct diff3_block *diff;
{
@@ -1638,42 +1637,43 @@ reverse_diff3_blocklist (diff)
tmp->next = prev;
prev = tmp;
}
-
+
return prev;
}
-int
+static int
myread (fd, ptr, size)
int fd, size;
char *ptr;
{
int result = read (fd, ptr, size);
if (result < 0)
- perror_with_exit ("Read failed");
+ perror_with_exit ("read failed");
return result;
}
VOID *
xmalloc (size)
- int size;
+ unsigned size;
{
VOID *result = (VOID *) malloc (size ? size : 1);
if (!result)
- fatal ("Malloc failed");
+ fatal ("virtual memory exhausted");
return result;
}
-VOID *
+static VOID *
xrealloc (ptr, size)
VOID *ptr;
- int size;
+ unsigned size;
{
VOID *result = (VOID *) realloc (ptr, size ? size : 1);
if (!result)
- fatal ("Malloc failed");
+ fatal ("virtual memory exhausted");
return result;
}
+static void
fatal (string)
char *string;
{
@@ -1681,9 +1681,13 @@ fatal (string)
exit (2);
}
+static void
perror_with_exit (string)
char *string;
{
+ int e = errno;
+ fprintf (stderr, "%s: ", argv0);
+ errno = e;
perror (string);
exit (2);
}