xref: /netbsd-src/external/gpl2/diffutils/dist/src/diff3.c (revision f8c23a2b94243924f9b7311eb0ad24bf23d5c657)
1*f8c23a2bSchristos /*	$NetBSD: diff3.c,v 1.2 2016/01/13 03:39:28 christos Exp $	*/
275f6d617Schristos 
375f6d617Schristos /* diff3 - compare three files line by line
475f6d617Schristos 
575f6d617Schristos    Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1998, 2001,
675f6d617Schristos    2002 Free Software Foundation, Inc.
775f6d617Schristos 
875f6d617Schristos    This program is free software; you can redistribute it and/or modify
975f6d617Schristos    it under the terms of the GNU General Public License as published by
1075f6d617Schristos    the Free Software Foundation; either version 2, or (at your option)
1175f6d617Schristos    any later version.
1275f6d617Schristos 
1375f6d617Schristos    This program is distributed in the hope that it will be useful,
1475f6d617Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1575f6d617Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1675f6d617Schristos    See the GNU General Public License for more details.
1775f6d617Schristos 
1875f6d617Schristos    You should have received a copy of the GNU General Public License
1975f6d617Schristos    along with this program; see the file COPYING.
2075f6d617Schristos    If not, write to the Free Software Foundation,
2175f6d617Schristos    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2275f6d617Schristos 
2375f6d617Schristos #include "system.h"
2475f6d617Schristos 
2575f6d617Schristos static char const copyright_string[] =
2675f6d617Schristos   "Copyright (C) 2002 Free Software Foundation, Inc.";
2775f6d617Schristos 
2875f6d617Schristos static char const authorship_msgid[] = N_("Written by Randy Smith.");
2975f6d617Schristos 
3075f6d617Schristos #include <c-stack.h>
3175f6d617Schristos #include <cmpbuf.h>
3275f6d617Schristos #include <error.h>
3375f6d617Schristos #include <exitfail.h>
3475f6d617Schristos #include <freesoft.h>
3575f6d617Schristos #include <getopt.h>
3675f6d617Schristos #include <inttostr.h>
3775f6d617Schristos #include <quotesys.h>
3875f6d617Schristos #include <stdio.h>
3975f6d617Schristos #include <xalloc.h>
4075f6d617Schristos 
4175f6d617Schristos extern char const version_string[];
4275f6d617Schristos 
4375f6d617Schristos /*
4475f6d617Schristos  * Internal data structures and macros for the diff3 program; includes
4575f6d617Schristos  * data structures for both diff3 diffs and normal diffs.
4675f6d617Schristos  */
4775f6d617Schristos 
4875f6d617Schristos /* Different files within a three way diff.  */
4975f6d617Schristos #define	FILE0	0
5075f6d617Schristos #define	FILE1	1
5175f6d617Schristos #define	FILE2	2
5275f6d617Schristos 
5375f6d617Schristos /*
5475f6d617Schristos  * A three way diff is built from two two-way diffs; the file which
5575f6d617Schristos  * the two two-way diffs share is:
5675f6d617Schristos  */
5775f6d617Schristos #define	FILEC	FILE2
5875f6d617Schristos 
5975f6d617Schristos /*
6075f6d617Schristos  * Different files within a two way diff.
6175f6d617Schristos  * FC is the common file, FO the other file.
6275f6d617Schristos  */
6375f6d617Schristos #define FO 0
6475f6d617Schristos #define FC 1
6575f6d617Schristos 
6675f6d617Schristos /* The ranges are indexed by */
6775f6d617Schristos #define	RANGE_START	0
6875f6d617Schristos #define	RANGE_END	1
6975f6d617Schristos 
7075f6d617Schristos enum diff_type {
7175f6d617Schristos   ERROR,			/* Should not be used */
7275f6d617Schristos   ADD,				/* Two way diff add */
7375f6d617Schristos   CHANGE,			/* Two way diff change */
7475f6d617Schristos   DELETE,			/* Two way diff delete */
7575f6d617Schristos   DIFF_ALL,			/* All three are different */
7675f6d617Schristos   DIFF_1ST,			/* Only the first is different */
7775f6d617Schristos   DIFF_2ND,			/* Only the second */
7875f6d617Schristos   DIFF_3RD			/* Only the third */
7975f6d617Schristos };
8075f6d617Schristos 
8175f6d617Schristos /* Two way diff */
8275f6d617Schristos struct diff_block {
8375f6d617Schristos   lin ranges[2][2];		/* Ranges are inclusive */
8475f6d617Schristos   char **lines[2];		/* The actual lines (may contain nulls) */
8575f6d617Schristos   size_t *lengths[2];		/* Line lengths (including newlines, if any) */
8675f6d617Schristos   struct diff_block *next;
8775f6d617Schristos };
8875f6d617Schristos 
8975f6d617Schristos /* Three way diff */
9075f6d617Schristos 
9175f6d617Schristos struct diff3_block {
9275f6d617Schristos   enum diff_type correspond;	/* Type of diff */
9375f6d617Schristos   lin ranges[3][2];		/* Ranges are inclusive */
9475f6d617Schristos   char **lines[3];		/* The actual lines (may contain nulls) */
9575f6d617Schristos   size_t *lengths[3];		/* Line lengths (including newlines, if any) */
9675f6d617Schristos   struct diff3_block *next;
9775f6d617Schristos };
9875f6d617Schristos 
9975f6d617Schristos /*
10075f6d617Schristos  * Access the ranges on a diff block.
10175f6d617Schristos  */
10275f6d617Schristos #define	D_LOWLINE(diff, filenum)	\
10375f6d617Schristos   ((diff)->ranges[filenum][RANGE_START])
10475f6d617Schristos #define	D_HIGHLINE(diff, filenum)	\
10575f6d617Schristos   ((diff)->ranges[filenum][RANGE_END])
10675f6d617Schristos #define	D_NUMLINES(diff, filenum)	\
10775f6d617Schristos   (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
10875f6d617Schristos 
10975f6d617Schristos /*
11075f6d617Schristos  * Access the line numbers in a file in a diff by relative line
11175f6d617Schristos  * numbers (i.e. line number within the diff itself).  Note that these
11275f6d617Schristos  * are lvalues and can be used for assignment.
11375f6d617Schristos  */
11475f6d617Schristos #define	D_RELNUM(diff, filenum, linenum)	\
11575f6d617Schristos   ((diff)->lines[filenum][linenum])
11675f6d617Schristos #define	D_RELLEN(diff, filenum, linenum)	\
11775f6d617Schristos   ((diff)->lengths[filenum][linenum])
11875f6d617Schristos 
11975f6d617Schristos /*
12075f6d617Schristos  * And get at them directly, when that should be necessary.
12175f6d617Schristos  */
12275f6d617Schristos #define	D_LINEARRAY(diff, filenum)	\
12375f6d617Schristos   ((diff)->lines[filenum])
12475f6d617Schristos #define	D_LENARRAY(diff, filenum)	\
12575f6d617Schristos   ((diff)->lengths[filenum])
12675f6d617Schristos 
12775f6d617Schristos /*
12875f6d617Schristos  * Next block.
12975f6d617Schristos  */
13075f6d617Schristos #define	D_NEXT(diff)	((diff)->next)
13175f6d617Schristos 
13275f6d617Schristos /*
13375f6d617Schristos  * Access the type of a diff3 block.
13475f6d617Schristos  */
13575f6d617Schristos #define	D3_TYPE(diff)	((diff)->correspond)
13675f6d617Schristos 
13775f6d617Schristos /*
13875f6d617Schristos  * Line mappings based on diffs.  The first maps off the top of the
13975f6d617Schristos  * diff, the second off of the bottom.
14075f6d617Schristos  */
14175f6d617Schristos #define	D_HIGH_MAPLINE(diff, fromfile, tofile, linenum)	\
14275f6d617Schristos   ((linenum)						\
14375f6d617Schristos    - D_HIGHLINE ((diff), (fromfile))			\
14475f6d617Schristos    + D_HIGHLINE ((diff), (tofile)))
14575f6d617Schristos 
14675f6d617Schristos #define	D_LOW_MAPLINE(diff, fromfile, tofile, linenum)	\
14775f6d617Schristos   ((linenum)						\
14875f6d617Schristos    - D_LOWLINE ((diff), (fromfile))			\
14975f6d617Schristos    + D_LOWLINE ((diff), (tofile)))
15075f6d617Schristos 
15175f6d617Schristos /* Options variables for flags set on command line.  */
15275f6d617Schristos 
15375f6d617Schristos /* If nonzero, treat all files as text files, never as binary.  */
15475f6d617Schristos static bool text;
15575f6d617Schristos 
15675f6d617Schristos /* If nonzero, write out an ed script instead of the standard diff3 format.  */
15775f6d617Schristos static bool edscript;
15875f6d617Schristos 
15975f6d617Schristos /* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
16075f6d617Schristos    preserve the lines which would normally be deleted from
16175f6d617Schristos    file 1 with a special flagging mechanism.  */
16275f6d617Schristos static bool flagging;
16375f6d617Schristos 
16475f6d617Schristos /* Use a tab to align output lines (-T).  */
16575f6d617Schristos static bool initial_tab;
16675f6d617Schristos 
16775f6d617Schristos /* If nonzero, do not output information for overlapping diffs.  */
16875f6d617Schristos static bool simple_only;
16975f6d617Schristos 
17075f6d617Schristos /* If nonzero, do not output information for non-overlapping diffs.  */
17175f6d617Schristos static bool overlap_only;
17275f6d617Schristos 
17375f6d617Schristos /* If nonzero, show information for DIFF_2ND diffs.  */
17475f6d617Schristos static bool show_2nd;
17575f6d617Schristos 
17675f6d617Schristos /* If nonzero, include `:wq' at the end of the script
17775f6d617Schristos    to write out the file being edited.   */
17875f6d617Schristos static bool finalwrite;
17975f6d617Schristos 
18075f6d617Schristos /* If nonzero, output a merged file.  */
18175f6d617Schristos static bool merge;
18275f6d617Schristos 
18375f6d617Schristos char *program_name;
18475f6d617Schristos 
18575f6d617Schristos static char *read_diff (char const *, char const *, char **);
18675f6d617Schristos static char *scan_diff_line (char *, char **, size_t *, char *, char);
18775f6d617Schristos static enum diff_type process_diff_control (char **, struct diff_block *);
18875f6d617Schristos static bool compare_line_list (char * const[], size_t const[], char * const[], size_t const[], lin);
18975f6d617Schristos static bool copy_stringlist (char * const[], size_t const[], char *[], size_t[], lin);
19075f6d617Schristos static bool output_diff3_edscript (FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
19175f6d617Schristos static bool output_diff3_merge (FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
19275f6d617Schristos static struct diff3_block *create_diff3_block (lin, lin, lin, lin, lin, lin);
19375f6d617Schristos static struct diff3_block *make_3way_diff (struct diff_block *, struct diff_block *);
19475f6d617Schristos static struct diff3_block *reverse_diff3_blocklist (struct diff3_block *);
19575f6d617Schristos static struct diff3_block *using_to_diff3_block (struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *);
19675f6d617Schristos static struct diff_block *process_diff (char const *, char const *, struct diff_block **);
19775f6d617Schristos static void check_stdout (void);
19875f6d617Schristos static void fatal (char const *) __attribute__((noreturn));
19975f6d617Schristos static void output_diff3 (FILE *, struct diff3_block *, int const[3], int const[3]);
20075f6d617Schristos static void perror_with_exit (char const *) __attribute__((noreturn));
20175f6d617Schristos static void try_help (char const *, char const *) __attribute__((noreturn));
20275f6d617Schristos static void usage (void);
20375f6d617Schristos 
20475f6d617Schristos static char const *diff_program = DEFAULT_DIFF_PROGRAM;
20575f6d617Schristos 
20675f6d617Schristos /* Values for long options that do not have single-letter equivalents.  */
20775f6d617Schristos enum
20875f6d617Schristos {
20975f6d617Schristos   DIFF_PROGRAM_OPTION = CHAR_MAX + 1,
21075f6d617Schristos   HELP_OPTION
21175f6d617Schristos };
21275f6d617Schristos 
21375f6d617Schristos static struct option const longopts[] =
21475f6d617Schristos {
21575f6d617Schristos   {"text", 0, 0, 'a'},
21675f6d617Schristos   {"show-all", 0, 0, 'A'},
21775f6d617Schristos   {"ed", 0, 0, 'e'},
21875f6d617Schristos   {"diff-program", 1, 0, DIFF_PROGRAM_OPTION},
21975f6d617Schristos   {"show-overlap", 0, 0, 'E'},
22075f6d617Schristos   {"label", 1, 0, 'L'},
22175f6d617Schristos   {"merge", 0, 0, 'm'},
22275f6d617Schristos   {"initial-tab", 0, 0, 'T'},
22375f6d617Schristos   {"overlap-only", 0, 0, 'x'},
22475f6d617Schristos   {"easy-only", 0, 0, '3'},
22575f6d617Schristos   {"version", 0, 0, 'v'},
22675f6d617Schristos   {"help", 0, 0, HELP_OPTION},
22775f6d617Schristos   {0, 0, 0, 0}
22875f6d617Schristos };
22975f6d617Schristos 
23075f6d617Schristos /*
23175f6d617Schristos  * Main program.  Calls diff twice on two pairs of input files,
23275f6d617Schristos  * combines the two diffs, and outputs them.
23375f6d617Schristos  */
23475f6d617Schristos int
main(int argc,char ** argv)23575f6d617Schristos main (int argc, char **argv)
23675f6d617Schristos {
23775f6d617Schristos   int c, i;
23875f6d617Schristos   int common;
23975f6d617Schristos   int mapping[3];
24075f6d617Schristos   int rev_mapping[3];
24175f6d617Schristos   int incompat = 0;
24275f6d617Schristos   bool conflicts_found;
24375f6d617Schristos   struct diff_block *thread0, *thread1, *last_block;
24475f6d617Schristos   struct diff3_block *diff3;
24575f6d617Schristos   int tag_count = 0;
24675f6d617Schristos   char *tag_strings[3];
24775f6d617Schristos   char *commonname;
24875f6d617Schristos   char **file;
24975f6d617Schristos   struct stat statb;
25075f6d617Schristos 
25175f6d617Schristos   exit_failure = 2;
25275f6d617Schristos   initialize_main (&argc, &argv);
25375f6d617Schristos   program_name = argv[0];
25475f6d617Schristos   setlocale (LC_ALL, "");
25575f6d617Schristos   bindtextdomain (PACKAGE, LOCALEDIR);
25675f6d617Schristos   textdomain (PACKAGE);
25775f6d617Schristos   c_stack_action (c_stack_die);
25875f6d617Schristos 
25975f6d617Schristos   while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != -1)
26075f6d617Schristos     {
26175f6d617Schristos       switch (c)
26275f6d617Schristos 	{
26375f6d617Schristos 	case 'a':
26475f6d617Schristos 	  text = 1;
26575f6d617Schristos 	  break;
26675f6d617Schristos 	case 'A':
26775f6d617Schristos 	  show_2nd = 1;
26875f6d617Schristos 	  flagging = 1;
26975f6d617Schristos 	  incompat++;
27075f6d617Schristos 	  break;
27175f6d617Schristos 	case 'x':
27275f6d617Schristos 	  overlap_only = 1;
27375f6d617Schristos 	  incompat++;
27475f6d617Schristos 	  break;
27575f6d617Schristos 	case '3':
27675f6d617Schristos 	  simple_only = 1;
27775f6d617Schristos 	  incompat++;
27875f6d617Schristos 	  break;
27975f6d617Schristos 	case 'i':
28075f6d617Schristos 	  finalwrite = 1;
28175f6d617Schristos 	  break;
28275f6d617Schristos 	case 'm':
28375f6d617Schristos 	  merge = 1;
28475f6d617Schristos 	  break;
28575f6d617Schristos 	case 'X':
28675f6d617Schristos 	  overlap_only = 1;
28775f6d617Schristos 	  /* Fall through.  */
28875f6d617Schristos 	case 'E':
28975f6d617Schristos 	  flagging = 1;
29075f6d617Schristos 	  /* Fall through.  */
29175f6d617Schristos 	case 'e':
29275f6d617Schristos 	  incompat++;
29375f6d617Schristos 	  break;
29475f6d617Schristos 	case 'T':
29575f6d617Schristos 	  initial_tab = 1;
29675f6d617Schristos 	  break;
29775f6d617Schristos 	case 'v':
29875f6d617Schristos 	  printf ("diff3 %s\n%s\n\n%s\n\n%s\n",
29975f6d617Schristos 		  version_string, copyright_string,
30075f6d617Schristos 		  _(free_software_msgid), _(authorship_msgid));
30175f6d617Schristos 	  check_stdout ();
30275f6d617Schristos 	  return EXIT_SUCCESS;
30375f6d617Schristos 	case DIFF_PROGRAM_OPTION:
30475f6d617Schristos 	  diff_program = optarg;
30575f6d617Schristos 	  break;
30675f6d617Schristos 	case HELP_OPTION:
30775f6d617Schristos 	  usage ();
30875f6d617Schristos 	  check_stdout ();
30975f6d617Schristos 	  return EXIT_SUCCESS;
31075f6d617Schristos 	case 'L':
31175f6d617Schristos 	  /* Handle up to three -L options.  */
31275f6d617Schristos 	  if (tag_count < 3)
31375f6d617Schristos 	    {
31475f6d617Schristos 	      tag_strings[tag_count++] = optarg;
31575f6d617Schristos 	      break;
31675f6d617Schristos 	    }
31775f6d617Schristos 	  try_help ("too many file label options", 0);
31875f6d617Schristos 	default:
31975f6d617Schristos 	  try_help (0, 0);
32075f6d617Schristos 	}
32175f6d617Schristos     }
32275f6d617Schristos 
32375f6d617Schristos   edscript = incompat & ~merge;  /* -AeExX3 without -m implies ed script.  */
32475f6d617Schristos   show_2nd |= ~incompat & merge;  /* -m without -AeExX3 implies -A.  */
32575f6d617Schristos   flagging |= ~incompat & merge;
32675f6d617Schristos 
32775f6d617Schristos   if (incompat > 1  /* Ensure at most one of -AeExX3.  */
32875f6d617Schristos       || finalwrite & merge /* -i -m would rewrite input file.  */
32975f6d617Schristos       || (tag_count && ! flagging)) /* -L requires one of -AEX.  */
33075f6d617Schristos     try_help ("incompatible options", 0);
33175f6d617Schristos 
33275f6d617Schristos   if (argc - optind != 3)
33375f6d617Schristos     {
33475f6d617Schristos       if (argc - optind < 3)
33575f6d617Schristos 	try_help ("missing operand after `%s'", argv[argc - 1]);
33675f6d617Schristos       else
33775f6d617Schristos 	try_help ("extra operand `%s'", argv[optind + 3]);
33875f6d617Schristos     }
33975f6d617Schristos 
34075f6d617Schristos   file = &argv[optind];
34175f6d617Schristos 
34275f6d617Schristos   for (i = tag_count; i < 3; i++)
34375f6d617Schristos     tag_strings[i] = file[i];
34475f6d617Schristos 
34575f6d617Schristos   /* Always compare file1 to file2, even if file2 is "-".
34675f6d617Schristos      This is needed for -mAeExX3.  Using the file0 as
34775f6d617Schristos      the common file would produce wrong results, because if the
34875f6d617Schristos      file0-file1 diffs didn't line up with the file0-file2 diffs
34975f6d617Schristos      (which is entirely possible since we don't use diff's -n option),
35075f6d617Schristos      diff3 might report phantom changes from file1 to file2.
35175f6d617Schristos 
35275f6d617Schristos      Also, try to compare file0 to file1, because this is where
35375f6d617Schristos      changes are expected to come from.  Diffing between these pairs
35475f6d617Schristos      of files is more likely to avoid phantom changes from file0 to file1.
35575f6d617Schristos 
35675f6d617Schristos      Historically, the default common file was file2, so some older
35775f6d617Schristos      applications (e.g. Emacs ediff) used file2 as the ancestor.  So,
35875f6d617Schristos      for compatibility, if this is a 3-way diff (not a merge or
35975f6d617Schristos      edscript), prefer file2 as the common file.  */
36075f6d617Schristos 
36175f6d617Schristos   common = 2 - (edscript | merge);
36275f6d617Schristos 
36375f6d617Schristos   if (strcmp (file[common], "-") == 0)
36475f6d617Schristos     {
36575f6d617Schristos       /* Sigh.  We've got standard input as the common file.  We can't
36675f6d617Schristos 	 call diff twice on stdin.  Use the other arg as the common
36775f6d617Schristos 	 file instead.  */
36875f6d617Schristos       common = 3 - common;
36975f6d617Schristos       if (strcmp (file[0], "-") == 0 || strcmp (file[common], "-") == 0)
37075f6d617Schristos 	fatal ("`-' specified for more than one input file");
37175f6d617Schristos     }
37275f6d617Schristos 
37375f6d617Schristos   mapping[0] = 0;
37475f6d617Schristos   mapping[1] = 3 - common;
37575f6d617Schristos   mapping[2] = common;
37675f6d617Schristos 
37775f6d617Schristos   for (i = 0; i < 3; i++)
37875f6d617Schristos     rev_mapping[mapping[i]] = i;
37975f6d617Schristos 
38075f6d617Schristos   for (i = 0; i < 3; i++)
38175f6d617Schristos     if (strcmp (file[i], "-") != 0)
38275f6d617Schristos       {
38375f6d617Schristos 	if (stat (file[i], &statb) < 0)
38475f6d617Schristos 	  perror_with_exit (file[i]);
38575f6d617Schristos 	else if (S_ISDIR (statb.st_mode))
38675f6d617Schristos 	  error (EXIT_TROUBLE, EISDIR, "%s", file[i]);
38775f6d617Schristos       }
38875f6d617Schristos 
38975f6d617Schristos #ifdef SIGCHLD
39075f6d617Schristos   /* System V fork+wait does not work if SIGCHLD is ignored.  */
39175f6d617Schristos   signal (SIGCHLD, SIG_DFL);
39275f6d617Schristos #endif
39375f6d617Schristos 
39475f6d617Schristos   commonname = file[rev_mapping[FILEC]];
39575f6d617Schristos   thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
39675f6d617Schristos   thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block);
39775f6d617Schristos   diff3 = make_3way_diff (thread0, thread1);
39875f6d617Schristos   if (edscript)
39975f6d617Schristos     conflicts_found
40075f6d617Schristos       = output_diff3_edscript (stdout, diff3, mapping, rev_mapping,
40175f6d617Schristos 			       tag_strings[0], tag_strings[1], tag_strings[2]);
40275f6d617Schristos   else if (merge)
40375f6d617Schristos     {
40475f6d617Schristos       if (! freopen (file[rev_mapping[FILE0]], "r", stdin))
40575f6d617Schristos 	perror_with_exit (file[rev_mapping[FILE0]]);
40675f6d617Schristos       conflicts_found
40775f6d617Schristos 	= output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping,
40875f6d617Schristos 			      tag_strings[0], tag_strings[1], tag_strings[2]);
40975f6d617Schristos       if (ferror (stdin))
41075f6d617Schristos 	fatal ("read failed");
41175f6d617Schristos     }
41275f6d617Schristos   else
41375f6d617Schristos     {
41475f6d617Schristos       output_diff3 (stdout, diff3, mapping, rev_mapping);
41575f6d617Schristos       conflicts_found = 0;
41675f6d617Schristos     }
41775f6d617Schristos 
41875f6d617Schristos   check_stdout ();
41975f6d617Schristos   exit (conflicts_found);
42075f6d617Schristos   return conflicts_found;
42175f6d617Schristos }
42275f6d617Schristos 
42375f6d617Schristos static void
try_help(char const * reason_msgid,char const * operand)42475f6d617Schristos try_help (char const *reason_msgid, char const *operand)
42575f6d617Schristos {
42675f6d617Schristos   if (reason_msgid)
42775f6d617Schristos     error (0, 0, _(reason_msgid), operand);
42875f6d617Schristos   error (EXIT_TROUBLE, 0,
42975f6d617Schristos 	 _("Try `%s --help' for more information."), program_name);
43075f6d617Schristos   abort ();
43175f6d617Schristos }
43275f6d617Schristos 
43375f6d617Schristos static void
check_stdout(void)43475f6d617Schristos check_stdout (void)
43575f6d617Schristos {
43675f6d617Schristos   if (ferror (stdout))
43775f6d617Schristos     fatal ("write failed");
43875f6d617Schristos   else if (fclose (stdout) != 0)
43975f6d617Schristos     perror_with_exit (_("standard output"));
44075f6d617Schristos }
44175f6d617Schristos 
44275f6d617Schristos static char const * const option_help_msgid[] = {
44375f6d617Schristos   N_("-e  --ed  Output unmerged changes from OLDFILE to YOURFILE into MYFILE."),
44475f6d617Schristos   N_("-E  --show-overlap  Output unmerged changes, bracketing conflicts."),
44575f6d617Schristos   N_("-A  --show-all  Output all changes, bracketing conflicts."),
44675f6d617Schristos   N_("-x  --overlap-only  Output overlapping changes."),
44775f6d617Schristos   N_("-X  Output overlapping changes, bracketing them."),
44875f6d617Schristos   N_("-3  --easy-only  Output unmerged nonoverlapping changes."),
44975f6d617Schristos   "",
45075f6d617Schristos   N_("-m  --merge  Output merged file instead of ed script (default -A)."),
45175f6d617Schristos   N_("-L LABEL  --label=LABEL  Use LABEL instead of file name."),
45275f6d617Schristos   N_("-i  Append `w' and `q' commands to ed scripts."),
45375f6d617Schristos   N_("-a  --text  Treat all files as text."),
45475f6d617Schristos   N_("-T  --initial-tab  Make tabs line up by prepending a tab."),
45575f6d617Schristos   N_("--diff-program=PROGRAM  Use PROGRAM to compare files."),
45675f6d617Schristos   "",
45775f6d617Schristos   N_("-v  --version  Output version info."),
45875f6d617Schristos   N_("--help  Output this help."),
45975f6d617Schristos   0
46075f6d617Schristos };
46175f6d617Schristos 
46275f6d617Schristos static void
usage(void)46375f6d617Schristos usage (void)
46475f6d617Schristos {
46575f6d617Schristos   char const * const *p;
46675f6d617Schristos 
46775f6d617Schristos   printf (_("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n"),
46875f6d617Schristos 	  program_name);
46975f6d617Schristos   printf ("%s\n\n", _("Compare three files line by line."));
47075f6d617Schristos   for (p = option_help_msgid;  *p;  p++)
47175f6d617Schristos     if (**p)
47275f6d617Schristos       printf ("  %s\n", _(*p));
47375f6d617Schristos     else
47475f6d617Schristos       putchar ('\n');
47575f6d617Schristos   printf ("\n%s\n\n%s\n",
47675f6d617Schristos 	  _("If a FILE is `-', read standard input."),
47775f6d617Schristos 	  _("Report bugs to <bug-gnu-utils@gnu.org>."));
47875f6d617Schristos }
47975f6d617Schristos 
48075f6d617Schristos /*
48175f6d617Schristos  * Routines that combine the two diffs together into one.  The
48275f6d617Schristos  * algorithm used follows:
48375f6d617Schristos  *
48475f6d617Schristos  *   File2 is shared in common between the two diffs.
48575f6d617Schristos  *   Diff02 is the diff between 0 and 2.
48675f6d617Schristos  *   Diff12 is the diff between 1 and 2.
48775f6d617Schristos  *
48875f6d617Schristos  *	1) Find the range for the first block in File2.
48975f6d617Schristos  *	    a) Take the lowest of the two ranges (in File2) in the two
49075f6d617Schristos  *	       current blocks (one from each diff) as being the low
49175f6d617Schristos  *	       water mark.  Assign the upper end of this block as
49275f6d617Schristos  *	       being the high water mark and move the current block up
49375f6d617Schristos  *	       one.  Mark the block just moved over as to be used.
49475f6d617Schristos  *	    b) Check the next block in the diff that the high water
49575f6d617Schristos  *	       mark is *not* from.
49675f6d617Schristos  *
49775f6d617Schristos  *	       *If* the high water mark is above
49875f6d617Schristos  *	       the low end of the range in that block,
49975f6d617Schristos  *
50075f6d617Schristos  *		   mark that block as to be used and move the current
50175f6d617Schristos  *		   block up.  Set the high water mark to the max of
50275f6d617Schristos  *		   the high end of this block and the current.  Repeat b.
50375f6d617Schristos  *
50475f6d617Schristos  *	 2) Find the corresponding ranges in File0 (from the blocks
50575f6d617Schristos  *	    in diff02; line per line outside of diffs) and in File1.
50675f6d617Schristos  *	    Create a diff3_block, reserving space as indicated by the ranges.
50775f6d617Schristos  *
50875f6d617Schristos  *	 3) Copy all of the pointers for file2 in.  At least for now,
50975f6d617Schristos  *	    do memcmp's between corresponding strings in the two diffs.
51075f6d617Schristos  *
51175f6d617Schristos  *	 4) Copy all of the pointers for file0 and 1 in.  Get what you
51275f6d617Schristos  *	    need from file2 (when there isn't a diff block, it's
51375f6d617Schristos  *	    identical to file2 within the range between diff blocks).
51475f6d617Schristos  *
51575f6d617Schristos  *	 5) If the diff blocks you used came from only one of the two
51675f6d617Schristos  *	    strings of diffs, then that file (i.e. the one other than
51775f6d617Schristos  *	    the common file in that diff) is the odd person out.  If you used
51875f6d617Schristos  *	    diff blocks from both sets, check to see if files 0 and 1 match:
51975f6d617Schristos  *
52075f6d617Schristos  *		Same number of lines?  If so, do a set of memcmp's (if a
52175f6d617Schristos  *	    memcmp matches; copy the pointer over; it'll be easier later
52275f6d617Schristos  *	    if you have to do any compares).  If they match, 0 & 1 are
52375f6d617Schristos  *	    the same.  If not, all three different.
52475f6d617Schristos  *
52575f6d617Schristos  *   Then you do it again, until you run out of blocks.
52675f6d617Schristos  *
52775f6d617Schristos  */
52875f6d617Schristos 
52975f6d617Schristos /*
53075f6d617Schristos  * This routine makes a three way diff (chain of diff3_block's) from two
53175f6d617Schristos  * two way diffs (chains of diff_block's).  It is assumed that each of
53275f6d617Schristos  * the two diffs passed are onto the same file (i.e. that each of the
53375f6d617Schristos  * diffs were made "to" the same file).  The three way diff pointer
53475f6d617Schristos  * returned will have numbering FILE0--the other file in diff02,
53575f6d617Schristos  * FILE1--the other file in diff12, and FILEC--the common file.
53675f6d617Schristos  */
53775f6d617Schristos static struct diff3_block *
make_3way_diff(struct diff_block * thread0,struct diff_block * thread1)53875f6d617Schristos make_3way_diff (struct diff_block *thread0, struct diff_block *thread1)
53975f6d617Schristos {
54075f6d617Schristos /*
54175f6d617Schristos  * This routine works on the two diffs passed to it as threads.
54275f6d617Schristos  * Thread number 0 is diff02, thread number 1 is diff12.  The USING
54375f6d617Schristos  * array is set to the base of the list of blocks to be used to
54475f6d617Schristos  * construct each block of the three way diff; if no blocks from a
54575f6d617Schristos  * particular thread are to be used, that element of the using array
54675f6d617Schristos  * is set to 0.  The elements LAST_USING array are set to the last
54775f6d617Schristos  * elements on each of the using lists.
54875f6d617Schristos  *
54975f6d617Schristos  * The HIGH_WATER_MARK is set to the highest line number in the common file
55075f6d617Schristos  * described in any of the diffs in either of the USING lists.  The
55175f6d617Schristos  * HIGH_WATER_THREAD names the thread.  Similarly the BASE_WATER_MARK
55275f6d617Schristos  * and BASE_WATER_THREAD describe the lowest line number in the common file
55375f6d617Schristos  * described in any of the diffs in either of the USING lists.  The
55475f6d617Schristos  * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
55575f6d617Schristos  * taken.
55675f6d617Schristos  *
55775f6d617Schristos  * The HIGH_WATER_DIFF should always be equal to LAST_USING
55875f6d617Schristos  * [HIGH_WATER_THREAD].  The OTHER_DIFF is the next diff to check for
55975f6d617Schristos  * higher water, and should always be equal to
56075f6d617Schristos  * CURRENT[HIGH_WATER_THREAD ^ 0x1].  The OTHER_THREAD is the thread
56175f6d617Schristos  * in which the OTHER_DIFF is, and hence should always be equal to
56275f6d617Schristos  * HIGH_WATER_THREAD ^ 0x1.
56375f6d617Schristos  *
56475f6d617Schristos  * The variable LAST_DIFF is kept set to the last diff block produced
56575f6d617Schristos  * by this routine, for line correspondence purposes between that diff
56675f6d617Schristos  * and the one currently being worked on.  It is initialized to
56775f6d617Schristos  * ZERO_DIFF before any blocks have been created.
56875f6d617Schristos  */
56975f6d617Schristos 
57075f6d617Schristos   struct diff_block *using[2];
57175f6d617Schristos   struct diff_block *last_using[2];
57275f6d617Schristos   struct diff_block *current[2];
57375f6d617Schristos 
57475f6d617Schristos   lin high_water_mark;
57575f6d617Schristos 
57675f6d617Schristos   int high_water_thread;
57775f6d617Schristos   int base_water_thread;
57875f6d617Schristos   int other_thread;
57975f6d617Schristos 
58075f6d617Schristos   struct diff_block *high_water_diff;
58175f6d617Schristos   struct diff_block *other_diff;
58275f6d617Schristos 
58375f6d617Schristos   struct diff3_block *result;
58475f6d617Schristos   struct diff3_block *tmpblock;
58575f6d617Schristos   struct diff3_block **result_end;
58675f6d617Schristos 
58775f6d617Schristos   struct diff3_block const *last_diff3;
58875f6d617Schristos 
58975f6d617Schristos   static struct diff3_block const zero_diff3;
59075f6d617Schristos 
59175f6d617Schristos   /* Initialization */
59275f6d617Schristos   result = 0;
59375f6d617Schristos   result_end = &result;
59475f6d617Schristos   current[0] = thread0; current[1] = thread1;
59575f6d617Schristos   last_diff3 = &zero_diff3;
59675f6d617Schristos 
59775f6d617Schristos   /* Sniff up the threads until we reach the end */
59875f6d617Schristos 
59975f6d617Schristos   while (current[0] || current[1])
60075f6d617Schristos     {
60175f6d617Schristos       using[0] = using[1] = last_using[0] = last_using[1] = 0;
60275f6d617Schristos 
60375f6d617Schristos       /* Setup low and high water threads, diffs, and marks.  */
60475f6d617Schristos       if (!current[0])
60575f6d617Schristos 	base_water_thread = 1;
60675f6d617Schristos       else if (!current[1])
60775f6d617Schristos 	base_water_thread = 0;
60875f6d617Schristos       else
60975f6d617Schristos 	base_water_thread =
61075f6d617Schristos 	  (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
61175f6d617Schristos 
61275f6d617Schristos       high_water_thread = base_water_thread;
61375f6d617Schristos 
61475f6d617Schristos       high_water_diff = current[high_water_thread];
61575f6d617Schristos 
61675f6d617Schristos       high_water_mark = D_HIGHLINE (high_water_diff, FC);
61775f6d617Schristos 
61875f6d617Schristos       /* Make the diff you just got info from into the using class */
61975f6d617Schristos       using[high_water_thread]
62075f6d617Schristos 	= last_using[high_water_thread]
62175f6d617Schristos 	= high_water_diff;
62275f6d617Schristos       current[high_water_thread] = high_water_diff->next;
62375f6d617Schristos       last_using[high_water_thread]->next = 0;
62475f6d617Schristos 
62575f6d617Schristos       /* And mark the other diff */
62675f6d617Schristos       other_thread = high_water_thread ^ 0x1;
62775f6d617Schristos       other_diff = current[other_thread];
62875f6d617Schristos 
62975f6d617Schristos       /* Shuffle up the ladder, checking the other diff to see if it
63075f6d617Schristos 	 needs to be incorporated.  */
63175f6d617Schristos       while (other_diff
63275f6d617Schristos 	     && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
63375f6d617Schristos 	{
63475f6d617Schristos 
63575f6d617Schristos 	  /* Incorporate this diff into the using list.  Note that
63675f6d617Schristos 	     this doesn't take it off the current list */
63775f6d617Schristos 	  if (using[other_thread])
63875f6d617Schristos 	    last_using[other_thread]->next = other_diff;
63975f6d617Schristos 	  else
64075f6d617Schristos 	    using[other_thread] = other_diff;
64175f6d617Schristos 	  last_using[other_thread] = other_diff;
64275f6d617Schristos 
64375f6d617Schristos 	  /* Take it off the current list.  Note that this following
64475f6d617Schristos 	     code assumes that other_diff enters it equal to
64575f6d617Schristos 	     current[high_water_thread ^ 0x1] */
64675f6d617Schristos 	  current[other_thread] = current[other_thread]->next;
64775f6d617Schristos 	  other_diff->next = 0;
64875f6d617Schristos 
64975f6d617Schristos 	  /* Set the high_water stuff
65075f6d617Schristos 	     If this comparison is equal, then this is the last pass
65175f6d617Schristos 	     through this loop; since diff blocks within a given
65275f6d617Schristos 	     thread cannot overlap, the high_water_mark will be
65375f6d617Schristos 	     *below* the range_start of either of the next diffs.  */
65475f6d617Schristos 
65575f6d617Schristos 	  if (high_water_mark < D_HIGHLINE (other_diff, FC))
65675f6d617Schristos 	    {
65775f6d617Schristos 	      high_water_thread ^= 1;
65875f6d617Schristos 	      high_water_diff = other_diff;
65975f6d617Schristos 	      high_water_mark = D_HIGHLINE (other_diff, FC);
66075f6d617Schristos 	    }
66175f6d617Schristos 
66275f6d617Schristos 	  /* Set the other diff */
66375f6d617Schristos 	  other_thread = high_water_thread ^ 0x1;
66475f6d617Schristos 	  other_diff = current[other_thread];
66575f6d617Schristos 	}
66675f6d617Schristos 
66775f6d617Schristos       /* The using lists contain a list of all of the blocks to be
66875f6d617Schristos 	 included in this diff3_block.  Create it.  */
66975f6d617Schristos 
67075f6d617Schristos       tmpblock = using_to_diff3_block (using, last_using,
67175f6d617Schristos 				       base_water_thread, high_water_thread,
67275f6d617Schristos 				       last_diff3);
67375f6d617Schristos 
67475f6d617Schristos       if (!tmpblock)
67575f6d617Schristos 	fatal ("internal error: screwup in format of diff blocks");
67675f6d617Schristos 
67775f6d617Schristos       /* Put it on the list.  */
67875f6d617Schristos       *result_end = tmpblock;
67975f6d617Schristos       result_end = &tmpblock->next;
68075f6d617Schristos 
68175f6d617Schristos       /* Set up corresponding lines correctly.  */
68275f6d617Schristos       last_diff3 = tmpblock;
68375f6d617Schristos     }
68475f6d617Schristos   return result;
68575f6d617Schristos }
68675f6d617Schristos 
68775f6d617Schristos /*
68875f6d617Schristos  * using_to_diff3_block:
68975f6d617Schristos  *   This routine takes two lists of blocks (from two separate diff
69075f6d617Schristos  * threads) and puts them together into one diff3 block.
69175f6d617Schristos  * It then returns a pointer to this diff3 block or 0 for failure.
69275f6d617Schristos  *
69375f6d617Schristos  * All arguments besides using are for the convenience of the routine;
69475f6d617Schristos  * they could be derived from the using array.
69575f6d617Schristos  * LAST_USING is a pair of pointers to the last blocks in the using
69675f6d617Schristos  * structure.
69775f6d617Schristos  * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
69875f6d617Schristos  * and highest line numbers for File0.
69975f6d617Schristos  * last_diff3 contains the last diff produced in the calling routine.
70075f6d617Schristos  * This is used for lines mappings which would still be identical to
70175f6d617Schristos  * the state that diff ended in.
70275f6d617Schristos  *
70375f6d617Schristos  * A distinction should be made in this routine between the two diffs
70475f6d617Schristos  * that are part of a normal two diff block, and the three diffs that
70575f6d617Schristos  * are part of a diff3_block.
70675f6d617Schristos  */
70775f6d617Schristos static struct diff3_block *
using_to_diff3_block(struct diff_block * using[2],struct diff_block * last_using[2],int low_thread,int high_thread,struct diff3_block const * last_diff3)70875f6d617Schristos using_to_diff3_block (struct diff_block *using[2],
70975f6d617Schristos 		      struct diff_block *last_using[2],
71075f6d617Schristos 		      int low_thread, int high_thread,
71175f6d617Schristos 		      struct diff3_block const *last_diff3)
71275f6d617Schristos {
71375f6d617Schristos   lin low[2], high[2];
71475f6d617Schristos   struct diff3_block *result;
71575f6d617Schristos   struct diff_block *ptr;
71675f6d617Schristos   int d;
71775f6d617Schristos   lin i;
71875f6d617Schristos 
71975f6d617Schristos   /* Find the range in the common file.  */
72075f6d617Schristos   lin lowc = D_LOWLINE (using[low_thread], FC);
72175f6d617Schristos   lin highc = D_HIGHLINE (last_using[high_thread], FC);
72275f6d617Schristos 
72375f6d617Schristos   /* Find the ranges in the other files.
72475f6d617Schristos      If using[d] is null, that means that the file to which that diff
72575f6d617Schristos      refers is equivalent to the common file over this range.  */
72675f6d617Schristos 
72775f6d617Schristos   for (d = 0; d < 2; d++)
72875f6d617Schristos     if (using[d])
72975f6d617Schristos       {
73075f6d617Schristos 	low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
73175f6d617Schristos 	high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
73275f6d617Schristos       }
73375f6d617Schristos     else
73475f6d617Schristos       {
73575f6d617Schristos 	low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
73675f6d617Schristos 	high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
73775f6d617Schristos       }
73875f6d617Schristos 
73975f6d617Schristos   /* Create a block with the appropriate sizes */
74075f6d617Schristos   result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
74175f6d617Schristos 
74275f6d617Schristos   /* Copy information for the common file.
74375f6d617Schristos      Return with a zero if any of the compares failed.  */
74475f6d617Schristos 
74575f6d617Schristos   for (d = 0; d < 2; d++)
74675f6d617Schristos     for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
74775f6d617Schristos       {
74875f6d617Schristos 	lin result_offset = D_LOWLINE (ptr, FC) - lowc;
74975f6d617Schristos 
75075f6d617Schristos 	if (!copy_stringlist (D_LINEARRAY (ptr, FC),
75175f6d617Schristos 			      D_LENARRAY (ptr, FC),
75275f6d617Schristos 			      D_LINEARRAY (result, FILEC) + result_offset,
75375f6d617Schristos 			      D_LENARRAY (result, FILEC) + result_offset,
75475f6d617Schristos 			      D_NUMLINES (ptr, FC)))
75575f6d617Schristos 	  return 0;
75675f6d617Schristos       }
75775f6d617Schristos 
75875f6d617Schristos   /* Copy information for file d.  First deal with anything that might be
75975f6d617Schristos      before the first diff.  */
76075f6d617Schristos 
76175f6d617Schristos   for (d = 0; d < 2; d++)
76275f6d617Schristos     {
76375f6d617Schristos       struct diff_block *u = using[d];
76475f6d617Schristos       lin lo = low[d], hi = high[d];
76575f6d617Schristos 
76675f6d617Schristos       for (i = 0;
76775f6d617Schristos 	   i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
76875f6d617Schristos 	   i++)
76975f6d617Schristos 	{
77075f6d617Schristos 	  D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
77175f6d617Schristos 	  D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
77275f6d617Schristos 	}
77375f6d617Schristos 
77475f6d617Schristos       for (ptr = u; ptr; ptr = D_NEXT (ptr))
77575f6d617Schristos 	{
77675f6d617Schristos 	  lin result_offset = D_LOWLINE (ptr, FO) - lo;
77775f6d617Schristos 	  lin linec;
77875f6d617Schristos 
77975f6d617Schristos 	  if (!copy_stringlist (D_LINEARRAY (ptr, FO),
78075f6d617Schristos 				D_LENARRAY (ptr, FO),
78175f6d617Schristos 				D_LINEARRAY (result, FILE0 + d) + result_offset,
78275f6d617Schristos 				D_LENARRAY (result, FILE0 + d) + result_offset,
78375f6d617Schristos 				D_NUMLINES (ptr, FO)))
78475f6d617Schristos 	    return 0;
78575f6d617Schristos 
78675f6d617Schristos 	  /* Catch the lines between here and the next diff */
78775f6d617Schristos 	  linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
78875f6d617Schristos 	  for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
78975f6d617Schristos 	       i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
79075f6d617Schristos 	       i++)
79175f6d617Schristos 	    {
79275f6d617Schristos 	      D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
79375f6d617Schristos 	      D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
79475f6d617Schristos 	      linec++;
79575f6d617Schristos 	    }
79675f6d617Schristos 	}
79775f6d617Schristos     }
79875f6d617Schristos 
79975f6d617Schristos   /* Set correspond */
80075f6d617Schristos   if (!using[0])
80175f6d617Schristos     D3_TYPE (result) = DIFF_2ND;
80275f6d617Schristos   else if (!using[1])
80375f6d617Schristos     D3_TYPE (result) = DIFF_1ST;
80475f6d617Schristos   else
80575f6d617Schristos     {
80675f6d617Schristos       lin nl0 = D_NUMLINES (result, FILE0);
80775f6d617Schristos       lin nl1 = D_NUMLINES (result, FILE1);
80875f6d617Schristos 
80975f6d617Schristos       if (nl0 != nl1
81075f6d617Schristos 	  || !compare_line_list (D_LINEARRAY (result, FILE0),
81175f6d617Schristos 				 D_LENARRAY (result, FILE0),
81275f6d617Schristos 				 D_LINEARRAY (result, FILE1),
81375f6d617Schristos 				 D_LENARRAY (result, FILE1),
81475f6d617Schristos 				 nl0))
81575f6d617Schristos 	D3_TYPE (result) = DIFF_ALL;
81675f6d617Schristos       else
81775f6d617Schristos 	D3_TYPE (result) = DIFF_3RD;
81875f6d617Schristos     }
81975f6d617Schristos 
82075f6d617Schristos   return result;
82175f6d617Schristos }
82275f6d617Schristos 
82375f6d617Schristos /*
82475f6d617Schristos  * This routine copies pointers from a list of strings to a different list
82575f6d617Schristos  * of strings.  If a spot in the second list is already filled, it
82675f6d617Schristos  * makes sure that it is filled with the same string; if not it
82775f6d617Schristos  * returns 0, the copy incomplete.
82875f6d617Schristos  * Upon successful completion of the copy, it returns 1.
82975f6d617Schristos  */
83075f6d617Schristos static bool
copy_stringlist(char * const fromptrs[],size_t const fromlengths[],char * toptrs[],size_t tolengths[],lin copynum)83175f6d617Schristos copy_stringlist (char * const fromptrs[], size_t const fromlengths[],
83275f6d617Schristos 		 char *toptrs[], size_t tolengths[],
83375f6d617Schristos 		 lin copynum)
83475f6d617Schristos {
83575f6d617Schristos   register char * const *f = fromptrs;
83675f6d617Schristos   register char **t = toptrs;
83775f6d617Schristos   register size_t const *fl = fromlengths;
83875f6d617Schristos   register size_t *tl = tolengths;
83975f6d617Schristos 
84075f6d617Schristos   while (copynum--)
84175f6d617Schristos     {
84275f6d617Schristos       if (*t)
84375f6d617Schristos 	{ if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; }
84475f6d617Schristos       else
84575f6d617Schristos 	{ *t = *f ; *tl = *fl; }
84675f6d617Schristos 
84775f6d617Schristos       t++; f++; tl++; fl++;
84875f6d617Schristos     }
84975f6d617Schristos   return 1;
85075f6d617Schristos }
85175f6d617Schristos 
85275f6d617Schristos /*
85375f6d617Schristos  * Create a diff3_block, with ranges as specified in the arguments.
85475f6d617Schristos  * Allocate the arrays for the various pointers (and zero them) based
85575f6d617Schristos  * on the arguments passed.  Return the block as a result.
85675f6d617Schristos  */
85775f6d617Schristos static struct diff3_block *
create_diff3_block(lin low0,lin high0,lin low1,lin high1,lin low2,lin high2)85875f6d617Schristos create_diff3_block (lin low0, lin high0,
85975f6d617Schristos 		    lin low1, lin high1,
86075f6d617Schristos 		    lin low2, lin high2)
86175f6d617Schristos {
86275f6d617Schristos   struct diff3_block *result = xmalloc (sizeof *result);
86375f6d617Schristos   lin numlines;
86475f6d617Schristos 
86575f6d617Schristos   D3_TYPE (result) = ERROR;
86675f6d617Schristos   D_NEXT (result) = 0;
86775f6d617Schristos 
86875f6d617Schristos   /* Assign ranges */
86975f6d617Schristos   D_LOWLINE (result, FILE0) = low0;
87075f6d617Schristos   D_HIGHLINE (result, FILE0) = high0;
87175f6d617Schristos   D_LOWLINE (result, FILE1) = low1;
87275f6d617Schristos   D_HIGHLINE (result, FILE1) = high1;
87375f6d617Schristos   D_LOWLINE (result, FILE2) = low2;
87475f6d617Schristos   D_HIGHLINE (result, FILE2) = high2;
87575f6d617Schristos 
87675f6d617Schristos   /* Allocate and zero space */
87775f6d617Schristos   numlines = D_NUMLINES (result, FILE0);
87875f6d617Schristos   if (numlines)
87975f6d617Schristos     {
88075f6d617Schristos       D_LINEARRAY (result, FILE0) = xcalloc (numlines, sizeof (char *));
88175f6d617Schristos       D_LENARRAY (result, FILE0) = xcalloc (numlines, sizeof (size_t));
88275f6d617Schristos     }
88375f6d617Schristos   else
88475f6d617Schristos     {
88575f6d617Schristos       D_LINEARRAY (result, FILE0) = 0;
88675f6d617Schristos       D_LENARRAY (result, FILE0) = 0;
88775f6d617Schristos     }
88875f6d617Schristos 
88975f6d617Schristos   numlines = D_NUMLINES (result, FILE1);
89075f6d617Schristos   if (numlines)
89175f6d617Schristos     {
89275f6d617Schristos       D_LINEARRAY (result, FILE1) = xcalloc (numlines, sizeof (char *));
89375f6d617Schristos       D_LENARRAY (result, FILE1) = xcalloc (numlines, sizeof (size_t));
89475f6d617Schristos     }
89575f6d617Schristos   else
89675f6d617Schristos     {
89775f6d617Schristos       D_LINEARRAY (result, FILE1) = 0;
89875f6d617Schristos       D_LENARRAY (result, FILE1) = 0;
89975f6d617Schristos     }
90075f6d617Schristos 
90175f6d617Schristos   numlines = D_NUMLINES (result, FILE2);
90275f6d617Schristos   if (numlines)
90375f6d617Schristos     {
90475f6d617Schristos       D_LINEARRAY (result, FILE2) = xcalloc (numlines, sizeof (char *));
90575f6d617Schristos       D_LENARRAY (result, FILE2) = xcalloc (numlines, sizeof (size_t));
90675f6d617Schristos     }
90775f6d617Schristos   else
90875f6d617Schristos     {
90975f6d617Schristos       D_LINEARRAY (result, FILE2) = 0;
91075f6d617Schristos       D_LENARRAY (result, FILE2) = 0;
91175f6d617Schristos     }
91275f6d617Schristos 
91375f6d617Schristos   /* Return */
91475f6d617Schristos   return result;
91575f6d617Schristos }
91675f6d617Schristos 
91775f6d617Schristos /*
91875f6d617Schristos  * Compare two lists of lines of text.
91975f6d617Schristos  * Return 1 if they are equivalent, 0 if not.
92075f6d617Schristos  */
92175f6d617Schristos static bool
compare_line_list(char * const list1[],size_t const lengths1[],char * const list2[],size_t const lengths2[],lin nl)92275f6d617Schristos compare_line_list (char * const list1[], size_t const lengths1[],
92375f6d617Schristos 		   char * const list2[], size_t const lengths2[],
92475f6d617Schristos 		   lin nl)
92575f6d617Schristos {
92675f6d617Schristos   char
92775f6d617Schristos     * const *l1 = list1,
92875f6d617Schristos     * const *l2 = list2;
92975f6d617Schristos   size_t const
93075f6d617Schristos     *lgths1 = lengths1,
93175f6d617Schristos     *lgths2 = lengths2;
93275f6d617Schristos 
93375f6d617Schristos   while (nl--)
93475f6d617Schristos     if (!*l1 || !*l2 || *lgths1 != *lgths2++
93575f6d617Schristos 	|| memcmp (*l1++, *l2++, *lgths1++))
93675f6d617Schristos       return 0;
93775f6d617Schristos   return 1;
93875f6d617Schristos }
93975f6d617Schristos 
94075f6d617Schristos /*
94175f6d617Schristos  * Routines to input and parse two way diffs.
94275f6d617Schristos  */
94375f6d617Schristos 
94475f6d617Schristos static struct diff_block *
process_diff(char const * filea,char const * fileb,struct diff_block ** last_block)94575f6d617Schristos process_diff (char const *filea,
94675f6d617Schristos 	      char const *fileb,
94775f6d617Schristos 	      struct diff_block **last_block)
94875f6d617Schristos {
94975f6d617Schristos   char *diff_contents;
95075f6d617Schristos   char *diff_limit;
95175f6d617Schristos   char *scan_diff;
95275f6d617Schristos   enum diff_type dt;
95375f6d617Schristos   lin i;
95475f6d617Schristos   struct diff_block *block_list, **block_list_end, *bptr;
95575f6d617Schristos   size_t too_many_lines = (PTRDIFF_MAX
95675f6d617Schristos 			   / MIN (sizeof *bptr->lines[1],
95775f6d617Schristos 				  sizeof *bptr->lengths[1]));
95875f6d617Schristos 
95975f6d617Schristos   diff_limit = read_diff (filea, fileb, &diff_contents);
96075f6d617Schristos   scan_diff = diff_contents;
96175f6d617Schristos   block_list_end = &block_list;
96275f6d617Schristos   bptr = 0; /* Pacify `gcc -W'.  */
96375f6d617Schristos 
96475f6d617Schristos   while (scan_diff < diff_limit)
96575f6d617Schristos     {
96675f6d617Schristos       bptr = xmalloc (sizeof *bptr);
96775f6d617Schristos       bptr->lines[0] = bptr->lines[1] = 0;
96875f6d617Schristos       bptr->lengths[0] = bptr->lengths[1] = 0;
96975f6d617Schristos 
97075f6d617Schristos       dt = process_diff_control (&scan_diff, bptr);
97175f6d617Schristos       if (dt == ERROR || *scan_diff != '\n')
97275f6d617Schristos 	{
97375f6d617Schristos 	  fprintf (stderr, _("%s: diff failed: "), program_name);
97475f6d617Schristos 	  do
97575f6d617Schristos 	    {
97675f6d617Schristos 	      putc (*scan_diff, stderr);
97775f6d617Schristos 	    }
97875f6d617Schristos 	  while (*scan_diff++ != '\n');
97975f6d617Schristos 	  exit (EXIT_TROUBLE);
98075f6d617Schristos 	}
98175f6d617Schristos       scan_diff++;
98275f6d617Schristos 
98375f6d617Schristos       /* Force appropriate ranges to be null, if necessary */
98475f6d617Schristos       switch (dt)
98575f6d617Schristos 	{
98675f6d617Schristos 	case ADD:
98775f6d617Schristos 	  bptr->ranges[0][0]++;
98875f6d617Schristos 	  break;
98975f6d617Schristos 	case DELETE:
99075f6d617Schristos 	  bptr->ranges[1][0]++;
99175f6d617Schristos 	  break;
99275f6d617Schristos 	case CHANGE:
99375f6d617Schristos 	  break;
99475f6d617Schristos 	default:
99575f6d617Schristos 	  fatal ("internal error: invalid diff type in process_diff");
99675f6d617Schristos 	  break;
99775f6d617Schristos 	}
99875f6d617Schristos 
99975f6d617Schristos       /* Allocate space for the pointers for the lines from filea, and
100075f6d617Schristos 	 parcel them out among these pointers */
100175f6d617Schristos       if (dt != ADD)
100275f6d617Schristos 	{
100375f6d617Schristos 	  lin numlines = D_NUMLINES (bptr, 0);
100475f6d617Schristos 	  if (too_many_lines <= numlines)
100575f6d617Schristos 	    xalloc_die ();
100675f6d617Schristos 	  bptr->lines[0] = xmalloc (numlines * sizeof *bptr->lines[0]);
100775f6d617Schristos 	  bptr->lengths[0] = xmalloc (numlines * sizeof *bptr->lengths[0]);
100875f6d617Schristos 	  for (i = 0; i < numlines; i++)
100975f6d617Schristos 	    scan_diff = scan_diff_line (scan_diff,
101075f6d617Schristos 					&(bptr->lines[0][i]),
101175f6d617Schristos 					&(bptr->lengths[0][i]),
101275f6d617Schristos 					diff_limit,
101375f6d617Schristos 					'<');
101475f6d617Schristos 	}
101575f6d617Schristos 
101675f6d617Schristos       /* Get past the separator for changes */
101775f6d617Schristos       if (dt == CHANGE)
101875f6d617Schristos 	{
101975f6d617Schristos 	  if (strncmp (scan_diff, "---\n", 4))
102075f6d617Schristos 	    fatal ("invalid diff format; invalid change separator");
102175f6d617Schristos 	  scan_diff += 4;
102275f6d617Schristos 	}
102375f6d617Schristos 
102475f6d617Schristos       /* Allocate space for the pointers for the lines from fileb, and
102575f6d617Schristos 	 parcel them out among these pointers */
102675f6d617Schristos       if (dt != DELETE)
102775f6d617Schristos 	{
102875f6d617Schristos 	  lin numlines = D_NUMLINES (bptr, 1);
102975f6d617Schristos 	  if (too_many_lines <= numlines)
103075f6d617Schristos 	    xalloc_die ();
103175f6d617Schristos 	  bptr->lines[1] = xmalloc (numlines * sizeof *bptr->lines[1]);
103275f6d617Schristos 	  bptr->lengths[1] = xmalloc (numlines * sizeof *bptr->lengths[1]);
103375f6d617Schristos 	  for (i = 0; i < numlines; i++)
103475f6d617Schristos 	    scan_diff = scan_diff_line (scan_diff,
103575f6d617Schristos 					&(bptr->lines[1][i]),
103675f6d617Schristos 					&(bptr->lengths[1][i]),
103775f6d617Schristos 					diff_limit,
103875f6d617Schristos 					'>');
103975f6d617Schristos 	}
104075f6d617Schristos 
104175f6d617Schristos       /* Place this block on the blocklist.  */
104275f6d617Schristos       *block_list_end = bptr;
104375f6d617Schristos       block_list_end = &bptr->next;
104475f6d617Schristos     }
104575f6d617Schristos 
104675f6d617Schristos   *block_list_end = 0;
104775f6d617Schristos   *last_block = bptr;
104875f6d617Schristos   return block_list;
104975f6d617Schristos }
105075f6d617Schristos 
105175f6d617Schristos /*
105275f6d617Schristos  * This routine will parse a normal format diff control string.  It
105375f6d617Schristos  * returns the type of the diff (ERROR if the format is bad).  All of
105475f6d617Schristos  * the other important information is filled into to the structure
105575f6d617Schristos  * pointed to by db, and the string pointer (whose location is passed
105675f6d617Schristos  * to this routine) is updated to point beyond the end of the string
105775f6d617Schristos  * parsed.  Note that only the ranges in the diff_block will be set by
105875f6d617Schristos  * this routine.
105975f6d617Schristos  *
106075f6d617Schristos  * If some specific pair of numbers has been reduced to a single
106175f6d617Schristos  * number, then both corresponding numbers in the diff block are set
106275f6d617Schristos  * to that number.  In general these numbers are interpreted as ranges
106375f6d617Schristos  * inclusive, unless being used by the ADD or DELETE commands.  It is
106475f6d617Schristos  * assumed that these will be special cased in a superior routine.
106575f6d617Schristos  */
106675f6d617Schristos 
106775f6d617Schristos static enum diff_type
process_diff_control(char ** string,struct diff_block * db)106875f6d617Schristos process_diff_control (char **string, struct diff_block *db)
106975f6d617Schristos {
107075f6d617Schristos   char *s = *string;
107175f6d617Schristos   lin holdnum;
107275f6d617Schristos   enum diff_type type;
107375f6d617Schristos 
107475f6d617Schristos /* These macros are defined here because they can use variables
107575f6d617Schristos    defined in this function.  Don't try this at home kids, we're
107675f6d617Schristos    trained professionals!
107775f6d617Schristos 
107875f6d617Schristos    Also note that SKIPWHITE only recognizes tabs and spaces, and
107975f6d617Schristos    that READNUM can only read positive, integral numbers */
108075f6d617Schristos 
108175f6d617Schristos #define	SKIPWHITE(s)	{ while (*s == ' ' || *s == '\t') s++; }
108275f6d617Schristos #define	READNUM(s, num)	\
108375f6d617Schristos 	{ unsigned char c = *s; if (!ISDIGIT (c)) return ERROR; holdnum = 0; \
108475f6d617Schristos 	  do { holdnum = (c - '0' + holdnum * 10); }	\
108575f6d617Schristos 	  while (ISDIGIT (c = *++s)); (num) = holdnum; }
108675f6d617Schristos 
108775f6d617Schristos   /* Read first set of digits */
108875f6d617Schristos   SKIPWHITE (s);
108975f6d617Schristos   READNUM (s, db->ranges[0][RANGE_START]);
109075f6d617Schristos 
109175f6d617Schristos   /* Was that the only digit? */
109275f6d617Schristos   SKIPWHITE (s);
109375f6d617Schristos   if (*s == ',')
109475f6d617Schristos     {
109575f6d617Schristos       /* Get the next digit */
109675f6d617Schristos       s++;
109775f6d617Schristos       READNUM (s, db->ranges[0][RANGE_END]);
109875f6d617Schristos     }
109975f6d617Schristos   else
110075f6d617Schristos     db->ranges[0][RANGE_END] = db->ranges[0][RANGE_START];
110175f6d617Schristos 
110275f6d617Schristos   /* Get the letter */
110375f6d617Schristos   SKIPWHITE (s);
110475f6d617Schristos   switch (*s)
110575f6d617Schristos     {
110675f6d617Schristos     case 'a':
110775f6d617Schristos       type = ADD;
110875f6d617Schristos       break;
110975f6d617Schristos     case 'c':
111075f6d617Schristos       type = CHANGE;
111175f6d617Schristos       break;
111275f6d617Schristos     case 'd':
111375f6d617Schristos       type = DELETE;
111475f6d617Schristos       break;
111575f6d617Schristos     default:
111675f6d617Schristos       return ERROR;			/* Bad format */
111775f6d617Schristos     }
111875f6d617Schristos   s++;				/* Past letter */
111975f6d617Schristos 
112075f6d617Schristos   /* Read second set of digits */
112175f6d617Schristos   SKIPWHITE (s);
112275f6d617Schristos   READNUM (s, db->ranges[1][RANGE_START]);
112375f6d617Schristos 
112475f6d617Schristos   /* Was that the only digit? */
112575f6d617Schristos   SKIPWHITE (s);
112675f6d617Schristos   if (*s == ',')
112775f6d617Schristos     {
112875f6d617Schristos       /* Get the next digit */
112975f6d617Schristos       s++;
113075f6d617Schristos       READNUM (s, db->ranges[1][RANGE_END]);
113175f6d617Schristos       SKIPWHITE (s);		/* To move to end */
113275f6d617Schristos     }
113375f6d617Schristos   else
113475f6d617Schristos     db->ranges[1][RANGE_END] = db->ranges[1][RANGE_START];
113575f6d617Schristos 
113675f6d617Schristos   *string = s;
113775f6d617Schristos   return type;
113875f6d617Schristos }
113975f6d617Schristos 
114075f6d617Schristos static char *
read_diff(char const * filea,char const * fileb,char ** output_placement)114175f6d617Schristos read_diff (char const *filea,
114275f6d617Schristos 	   char const *fileb,
114375f6d617Schristos 	   char **output_placement)
114475f6d617Schristos {
114575f6d617Schristos   char *diff_result;
114675f6d617Schristos   size_t current_chunk_size, total;
114775f6d617Schristos   int fd, wstatus;
114875f6d617Schristos   int werrno = 0;
114975f6d617Schristos   struct stat pipestat;
115075f6d617Schristos 
115175f6d617Schristos #if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
115275f6d617Schristos 
115375f6d617Schristos   char const *argv[8];
115475f6d617Schristos   char const **ap;
115575f6d617Schristos   int fds[2];
115675f6d617Schristos   pid_t pid;
115775f6d617Schristos 
115875f6d617Schristos   ap = argv;
115975f6d617Schristos   *ap++ = diff_program;
116075f6d617Schristos   if (text)
116175f6d617Schristos     *ap++ = "-a";
116275f6d617Schristos   *ap++ = "--horizon-lines=100";
116375f6d617Schristos   *ap++ = "--";
116475f6d617Schristos   *ap++ = filea;
116575f6d617Schristos   *ap++ = fileb;
116675f6d617Schristos   *ap = 0;
116775f6d617Schristos 
116875f6d617Schristos   if (pipe (fds) != 0)
116975f6d617Schristos     perror_with_exit ("pipe");
117075f6d617Schristos 
117175f6d617Schristos   pid = vfork ();
117275f6d617Schristos   if (pid == 0)
117375f6d617Schristos     {
117475f6d617Schristos       /* Child */
117575f6d617Schristos       close (fds[0]);
117675f6d617Schristos       if (fds[1] != STDOUT_FILENO)
117775f6d617Schristos 	{
117875f6d617Schristos 	  dup2 (fds[1], STDOUT_FILENO);
117975f6d617Schristos 	  close (fds[1]);
118075f6d617Schristos 	}
118175f6d617Schristos 
118275f6d617Schristos       /* The cast to (char **) is needed for portability to older
118375f6d617Schristos 	 hosts with a nonstandard prototype for execvp.  */
118475f6d617Schristos       execvp (diff_program, (char **) argv);
118575f6d617Schristos 
118675f6d617Schristos       _exit (errno == ENOEXEC ? 126 : 127);
118775f6d617Schristos     }
118875f6d617Schristos 
118975f6d617Schristos   if (pid == -1)
119075f6d617Schristos     perror_with_exit ("fork");
119175f6d617Schristos 
119275f6d617Schristos   close (fds[1]);		/* Prevent erroneous lack of EOF */
119375f6d617Schristos   fd = fds[0];
119475f6d617Schristos 
119575f6d617Schristos #else
119675f6d617Schristos 
119775f6d617Schristos   FILE *fpipe;
119875f6d617Schristos   char const args[] = " -a --horizon-lines=100 -- ";
119975f6d617Schristos   char *command = xmalloc (quote_system_arg (0, diff_program)
120075f6d617Schristos 			   + sizeof args - 1
120175f6d617Schristos 			   + quote_system_arg (0, filea) + 1
120275f6d617Schristos 			   + quote_system_arg (0, fileb) + 1);
120375f6d617Schristos   char *p = command;
120475f6d617Schristos   p += quote_system_arg (p, diff_program);
120575f6d617Schristos   strcpy (p, args + (text ? 0 : 3));
120675f6d617Schristos   p += strlen (p);
120775f6d617Schristos   p += quote_system_arg (p, filea);
120875f6d617Schristos   *p++ = ' ';
120975f6d617Schristos   p += quote_system_arg (p, fileb);
121075f6d617Schristos   *p = 0;
121175f6d617Schristos   errno = 0;
121275f6d617Schristos   fpipe = popen (command, "r");
121375f6d617Schristos   if (!fpipe)
121475f6d617Schristos     perror_with_exit (command);
121575f6d617Schristos   free (command);
121675f6d617Schristos   fd = fileno (fpipe);
121775f6d617Schristos 
121875f6d617Schristos #endif
121975f6d617Schristos 
122075f6d617Schristos   if (fstat (fd, &pipestat) != 0)
122175f6d617Schristos     perror_with_exit ("fstat");
122275f6d617Schristos   current_chunk_size = MAX (1, STAT_BLOCKSIZE (pipestat));
122375f6d617Schristos   diff_result = xmalloc (current_chunk_size);
122475f6d617Schristos   total = 0;
122575f6d617Schristos 
122675f6d617Schristos   for (;;)
122775f6d617Schristos     {
122875f6d617Schristos       size_t bytes_to_read = current_chunk_size - total;
122975f6d617Schristos       size_t bytes = block_read (fd, diff_result + total, bytes_to_read);
123075f6d617Schristos       total += bytes;
123175f6d617Schristos       if (bytes != bytes_to_read)
123275f6d617Schristos 	{
123375f6d617Schristos 	  if (bytes == SIZE_MAX)
123475f6d617Schristos 	    perror_with_exit (_("read failed"));
123575f6d617Schristos 	  break;
123675f6d617Schristos 	}
123775f6d617Schristos       if (PTRDIFF_MAX / 2 <= current_chunk_size)
123875f6d617Schristos 	xalloc_die ();
123975f6d617Schristos       current_chunk_size *= 2;
124075f6d617Schristos       diff_result = xrealloc (diff_result, current_chunk_size);
124175f6d617Schristos     }
124275f6d617Schristos 
124375f6d617Schristos   if (total != 0 && diff_result[total-1] != '\n')
124475f6d617Schristos     fatal ("invalid diff format; incomplete last line");
124575f6d617Schristos 
124675f6d617Schristos   *output_placement = diff_result;
124775f6d617Schristos 
124875f6d617Schristos #if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
124975f6d617Schristos 
125075f6d617Schristos   wstatus = pclose (fpipe);
125175f6d617Schristos   if (wstatus == -1)
125275f6d617Schristos     werrno = errno;
125375f6d617Schristos 
125475f6d617Schristos #else
125575f6d617Schristos 
125675f6d617Schristos   if (close (fd) != 0)
125775f6d617Schristos     perror_with_exit ("close");
125875f6d617Schristos   if (waitpid (pid, &wstatus, 0) < 0)
125975f6d617Schristos     perror_with_exit ("waitpid");
126075f6d617Schristos 
126175f6d617Schristos #endif
126275f6d617Schristos 
126375f6d617Schristos   if (! werrno && WIFEXITED (wstatus))
126475f6d617Schristos     switch (WEXITSTATUS (wstatus))
126575f6d617Schristos       {
126675f6d617Schristos       case 126:
126775f6d617Schristos 	error (EXIT_TROUBLE, 0, _("subsidiary program `%s' not executable"),
126875f6d617Schristos 	       diff_program);
126975f6d617Schristos       case 127:
127075f6d617Schristos 	error (EXIT_TROUBLE, 0, _("subsidiary program `%s' not found"),
127175f6d617Schristos 	       diff_program);
127275f6d617Schristos       }
127375f6d617Schristos   if (werrno || ! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
127475f6d617Schristos     error (EXIT_TROUBLE, werrno, _("subsidiary program `%s' failed"),
127575f6d617Schristos 	   diff_program);
127675f6d617Schristos 
127775f6d617Schristos   return diff_result + total;
127875f6d617Schristos }
127975f6d617Schristos 
128075f6d617Schristos 
128175f6d617Schristos /*
128275f6d617Schristos  * Scan a regular diff line (consisting of > or <, followed by a
128375f6d617Schristos  * space, followed by text (including nulls) up to a newline.
128475f6d617Schristos  *
128575f6d617Schristos  * This next routine began life as a macro and many parameters in it
128675f6d617Schristos  * are used as call-by-reference values.
128775f6d617Schristos  */
128875f6d617Schristos static char *
scan_diff_line(char * scan_ptr,char ** set_start,size_t * set_length,char * limit,char leadingchar)128975f6d617Schristos scan_diff_line (char *scan_ptr, char **set_start, size_t *set_length,
129075f6d617Schristos 		char *limit, char leadingchar)
129175f6d617Schristos {
129275f6d617Schristos   char *line_ptr;
129375f6d617Schristos 
129475f6d617Schristos   if (!(scan_ptr[0] == leadingchar
129575f6d617Schristos 	&& scan_ptr[1] == ' '))
129675f6d617Schristos     fatal ("invalid diff format; incorrect leading line chars");
129775f6d617Schristos 
129875f6d617Schristos   *set_start = line_ptr = scan_ptr + 2;
129975f6d617Schristos   while (*line_ptr++ != '\n')
130075f6d617Schristos     continue;
130175f6d617Schristos 
130275f6d617Schristos   /* Include newline if the original line ended in a newline,
130375f6d617Schristos      or if an edit script is being generated.
130475f6d617Schristos      Copy any missing newline message to stderr if an edit script is being
130575f6d617Schristos      generated, because edit scripts cannot handle missing newlines.
130675f6d617Schristos      Return the beginning of the next line.  */
130775f6d617Schristos   *set_length = line_ptr - *set_start;
130875f6d617Schristos   if (line_ptr < limit && *line_ptr == '\\')
130975f6d617Schristos     {
131075f6d617Schristos       if (edscript)
131175f6d617Schristos 	fprintf (stderr, "%s:", program_name);
131275f6d617Schristos       else
131375f6d617Schristos 	--*set_length;
131475f6d617Schristos       line_ptr++;
131575f6d617Schristos       do
131675f6d617Schristos 	{
131775f6d617Schristos 	  if (edscript)
131875f6d617Schristos 	    putc (*line_ptr, stderr);
131975f6d617Schristos 	}
132075f6d617Schristos       while (*line_ptr++ != '\n');
132175f6d617Schristos     }
132275f6d617Schristos 
132375f6d617Schristos   return line_ptr;
132475f6d617Schristos }
132575f6d617Schristos 
132675f6d617Schristos /*
132775f6d617Schristos  * This routine outputs a three way diff passed as a list of
132875f6d617Schristos  * diff3_block's.
132975f6d617Schristos  * The argument MAPPING is indexed by external file number (in the
133075f6d617Schristos  * argument list) and contains the internal file number (from the
133175f6d617Schristos  * diff passed).  This is important because the user expects his
133275f6d617Schristos  * outputs in terms of the argument list number, and the diff passed
133375f6d617Schristos  * may have been done slightly differently (if the last argument
133475f6d617Schristos  * was "-", for example).
133575f6d617Schristos  * REV_MAPPING is the inverse of MAPPING.
133675f6d617Schristos  */
133775f6d617Schristos static void
output_diff3(FILE * outputfile,struct diff3_block * diff,int const mapping[3],int const rev_mapping[3])133875f6d617Schristos output_diff3 (FILE *outputfile, struct diff3_block *diff,
133975f6d617Schristos 	      int const mapping[3], int const rev_mapping[3])
134075f6d617Schristos {
134175f6d617Schristos   int i;
134275f6d617Schristos   int oddoneout;
134375f6d617Schristos   char *cp;
134475f6d617Schristos   struct diff3_block *ptr;
134575f6d617Schristos   lin line;
134675f6d617Schristos   size_t length;
134775f6d617Schristos   int dontprint;
134875f6d617Schristos   static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
134975f6d617Schristos   char const *line_prefix = initial_tab ? "\t" : "  ";
135075f6d617Schristos 
135175f6d617Schristos   for (ptr = diff; ptr; ptr = D_NEXT (ptr))
135275f6d617Schristos     {
135375f6d617Schristos       char x[2];
135475f6d617Schristos 
135575f6d617Schristos       switch (ptr->correspond)
135675f6d617Schristos 	{
135775f6d617Schristos 	case DIFF_ALL:
135875f6d617Schristos 	  x[0] = 0;
135975f6d617Schristos 	  dontprint = 3;	/* Print them all */
136075f6d617Schristos 	  oddoneout = 3;	/* Nobody's odder than anyone else */
136175f6d617Schristos 	  break;
136275f6d617Schristos 	case DIFF_1ST:
136375f6d617Schristos 	case DIFF_2ND:
136475f6d617Schristos 	case DIFF_3RD:
136575f6d617Schristos 	  oddoneout = rev_mapping[ptr->correspond - DIFF_1ST];
136675f6d617Schristos 
136775f6d617Schristos 	  x[0] = oddoneout + '1';
136875f6d617Schristos 	  x[1] = 0;
136975f6d617Schristos 	  dontprint = oddoneout == 0;
137075f6d617Schristos 	  break;
137175f6d617Schristos 	default:
137275f6d617Schristos 	  fatal ("internal error: invalid diff type passed to output");
137375f6d617Schristos 	}
137475f6d617Schristos       fprintf (outputfile, "====%s\n", x);
137575f6d617Schristos 
137675f6d617Schristos       /* Go 0, 2, 1 if the first and third outputs are equivalent.  */
137775f6d617Schristos       for (i = 0; i < 3;
137875f6d617Schristos 	   i = (oddoneout == 1 ? skew_increment[i] : i + 1))
137975f6d617Schristos 	{
138075f6d617Schristos 	  int realfile = mapping[i];
138175f6d617Schristos 	  lin lowt = D_LOWLINE (ptr, realfile);
138275f6d617Schristos 	  lin hight = D_HIGHLINE (ptr, realfile);
138375f6d617Schristos 	  long llowt = lowt;
138475f6d617Schristos 	  long lhight = hight;
138575f6d617Schristos 
138675f6d617Schristos 	  fprintf (outputfile, "%d:", i + 1);
138775f6d617Schristos 	  switch (lowt - hight)
138875f6d617Schristos 	    {
138975f6d617Schristos 	    case 1:
139075f6d617Schristos 	      fprintf (outputfile, "%lda\n", llowt - 1);
139175f6d617Schristos 	      break;
139275f6d617Schristos 	    case 0:
139375f6d617Schristos 	      fprintf (outputfile, "%ldc\n", llowt);
139475f6d617Schristos 	      break;
139575f6d617Schristos 	    default:
139675f6d617Schristos 	      fprintf (outputfile, "%ld,%ldc\n", llowt, lhight);
139775f6d617Schristos 	      break;
139875f6d617Schristos 	    }
139975f6d617Schristos 
140075f6d617Schristos 	  if (i == dontprint) continue;
140175f6d617Schristos 
140275f6d617Schristos 	  if (lowt <= hight)
140375f6d617Schristos 	    {
140475f6d617Schristos 	      line = 0;
140575f6d617Schristos 	      do
140675f6d617Schristos 		{
1407*f8c23a2bSchristos 		  fprintf (outputfile, "%s", line_prefix);
140875f6d617Schristos 		  cp = D_RELNUM (ptr, realfile, line);
140975f6d617Schristos 		  length = D_RELLEN (ptr, realfile, line);
141075f6d617Schristos 		  fwrite (cp, sizeof (char), length, outputfile);
141175f6d617Schristos 		}
141275f6d617Schristos 	      while (++line < hight - lowt + 1);
141375f6d617Schristos 	      if (cp[length - 1] != '\n')
141475f6d617Schristos 		fprintf (outputfile, "\n\\ %s\n",
141575f6d617Schristos 			 _("No newline at end of file"));
141675f6d617Schristos 	    }
141775f6d617Schristos 	}
141875f6d617Schristos     }
141975f6d617Schristos }
142075f6d617Schristos 
142175f6d617Schristos 
142275f6d617Schristos /*
142375f6d617Schristos  * Output to OUTPUTFILE the lines of B taken from FILENUM.
142475f6d617Schristos  * Double any initial '.'s; yield nonzero if any initial '.'s were doubled.
142575f6d617Schristos  */
142675f6d617Schristos static bool
dotlines(FILE * outputfile,struct diff3_block * b,int filenum)142775f6d617Schristos dotlines (FILE *outputfile, struct diff3_block *b, int filenum)
142875f6d617Schristos {
142975f6d617Schristos   lin i;
143075f6d617Schristos   bool leading_dot = 0;
143175f6d617Schristos 
143275f6d617Schristos   for (i = 0;
143375f6d617Schristos        i < D_NUMLINES (b, filenum);
143475f6d617Schristos        i++)
143575f6d617Schristos     {
143675f6d617Schristos       char *line = D_RELNUM (b, filenum, i);
143775f6d617Schristos       if (line[0] == '.')
143875f6d617Schristos 	{
143975f6d617Schristos 	  leading_dot = 1;
144075f6d617Schristos 	  fprintf (outputfile, ".");
144175f6d617Schristos 	}
144275f6d617Schristos       fwrite (line, sizeof (char),
144375f6d617Schristos 	      D_RELLEN (b, filenum, i), outputfile);
144475f6d617Schristos     }
144575f6d617Schristos 
144675f6d617Schristos   return leading_dot;
144775f6d617Schristos }
144875f6d617Schristos 
144975f6d617Schristos /*
145075f6d617Schristos  * Output to OUTPUTFILE a '.' line.  If LEADING_DOT is nonzero,
145175f6d617Schristos  * also output a command that removes initial '.'s
145275f6d617Schristos  * starting with line START and continuing for NUM lines.
145375f6d617Schristos  * (START is long, not lin, for convenience with printf %ld formats.)
145475f6d617Schristos  */
145575f6d617Schristos static void
undotlines(FILE * outputfile,bool leading_dot,long start,lin num)145675f6d617Schristos undotlines (FILE *outputfile, bool leading_dot, long start, lin num)
145775f6d617Schristos {
145875f6d617Schristos   fprintf (outputfile, ".\n");
145975f6d617Schristos   if (leading_dot)
146075f6d617Schristos     {
146175f6d617Schristos       if (num == 1)
146275f6d617Schristos 	fprintf (outputfile, "%lds/^\\.//\n", start);
146375f6d617Schristos       else
146475f6d617Schristos 	fprintf (outputfile, "%ld,%lds/^\\.//\n", start, start + num - 1);
146575f6d617Schristos     }
146675f6d617Schristos }
146775f6d617Schristos 
146875f6d617Schristos /*
146975f6d617Schristos  * This routine outputs a diff3 set of blocks as an ed script.  This
147075f6d617Schristos  * script applies the changes between file's 2 & 3 to file 1.  It
147175f6d617Schristos  * takes the precise format of the ed script to be output from global
147275f6d617Schristos  * variables set during options processing.  Note that it does
147375f6d617Schristos  * destructive things to the set of diff3 blocks it is passed; it
147475f6d617Schristos  * reverses their order (this gets around the problems involved with
147575f6d617Schristos  * changing line numbers in an ed script).
147675f6d617Schristos  *
147775f6d617Schristos  * Note that this routine has the same problem of mapping as the last
147875f6d617Schristos  * one did; the variable MAPPING maps from file number according to
147975f6d617Schristos  * the argument list to file number according to the diff passed.  All
148075f6d617Schristos  * files listed below are in terms of the argument list.
148175f6d617Schristos  * REV_MAPPING is the inverse of MAPPING.
148275f6d617Schristos  *
148375f6d617Schristos  * The arguments FILE0, FILE1 and FILE2 are the strings to print
148475f6d617Schristos  * as the names of the three files.  These may be the actual names,
148575f6d617Schristos  * or may be the arguments specified with -L.
148675f6d617Schristos  *
148775f6d617Schristos  * Returns 1 if conflicts were found.
148875f6d617Schristos  */
148975f6d617Schristos 
149075f6d617Schristos static bool
output_diff3_edscript(FILE * outputfile,struct diff3_block * diff,int const mapping[3],int const rev_mapping[3],char const * file0,char const * file1,char const * file2)149175f6d617Schristos output_diff3_edscript (FILE *outputfile, struct diff3_block *diff,
149275f6d617Schristos 		       int const mapping[3], int const rev_mapping[3],
149375f6d617Schristos 		       char const *file0, char const *file1, char const *file2)
149475f6d617Schristos {
149575f6d617Schristos   bool leading_dot;
149675f6d617Schristos   bool conflicts_found = 0, conflict;
149775f6d617Schristos   struct diff3_block *b;
149875f6d617Schristos 
149975f6d617Schristos   for (b = reverse_diff3_blocklist (diff); b; b = b->next)
150075f6d617Schristos     {
150175f6d617Schristos       /* Must do mapping correctly.  */
150275f6d617Schristos       enum diff_type type
150375f6d617Schristos 	= (b->correspond == DIFF_ALL
150475f6d617Schristos 	   ? DIFF_ALL
150575f6d617Schristos 	   : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
150675f6d617Schristos 
150775f6d617Schristos       long low0, high0;
150875f6d617Schristos 
150975f6d617Schristos       /* If we aren't supposed to do this output block, skip it.  */
151075f6d617Schristos       switch (type)
151175f6d617Schristos 	{
151275f6d617Schristos 	default: continue;
151375f6d617Schristos 	case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
151475f6d617Schristos 	case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
151575f6d617Schristos 	case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
151675f6d617Schristos 	}
151775f6d617Schristos 
151875f6d617Schristos       low0 = D_LOWLINE (b, mapping[FILE0]);
151975f6d617Schristos       high0 = D_HIGHLINE (b, mapping[FILE0]);
152075f6d617Schristos 
152175f6d617Schristos       if (conflict)
152275f6d617Schristos 	{
152375f6d617Schristos 	  conflicts_found = 1;
152475f6d617Schristos 
152575f6d617Schristos 
152675f6d617Schristos 	  /* Mark end of conflict.  */
152775f6d617Schristos 
152875f6d617Schristos 	  fprintf (outputfile, "%lda\n", high0);
152975f6d617Schristos 	  leading_dot = 0;
153075f6d617Schristos 	  if (type == DIFF_ALL)
153175f6d617Schristos 	    {
153275f6d617Schristos 	      if (show_2nd)
153375f6d617Schristos 		{
153475f6d617Schristos 		  /* Append lines from FILE1.  */
153575f6d617Schristos 		  fprintf (outputfile, "||||||| %s\n", file1);
153675f6d617Schristos 		  leading_dot = dotlines (outputfile, b, mapping[FILE1]);
153775f6d617Schristos 		}
153875f6d617Schristos 	      /* Append lines from FILE2.  */
153975f6d617Schristos 	      fprintf (outputfile, "=======\n");
154075f6d617Schristos 	      leading_dot |= dotlines (outputfile, b, mapping[FILE2]);
154175f6d617Schristos 	    }
154275f6d617Schristos 	  fprintf (outputfile, ">>>>>>> %s\n", file2);
154375f6d617Schristos 	  undotlines (outputfile, leading_dot, high0 + 2,
154475f6d617Schristos 		      (D_NUMLINES (b, mapping[FILE1])
154575f6d617Schristos 		       + D_NUMLINES (b, mapping[FILE2]) + 1));
154675f6d617Schristos 
154775f6d617Schristos 
154875f6d617Schristos 	  /* Mark start of conflict.  */
154975f6d617Schristos 
155075f6d617Schristos 	  fprintf (outputfile, "%lda\n<<<<<<< %s\n", low0 - 1,
155175f6d617Schristos 		   type == DIFF_ALL ? file0 : file1);
155275f6d617Schristos 	  leading_dot = 0;
155375f6d617Schristos 	  if (type == DIFF_2ND)
155475f6d617Schristos 	    {
155575f6d617Schristos 	      /* Prepend lines from FILE1.  */
155675f6d617Schristos 	      leading_dot = dotlines (outputfile, b, mapping[FILE1]);
155775f6d617Schristos 	      fprintf (outputfile, "=======\n");
155875f6d617Schristos 	    }
155975f6d617Schristos 	  undotlines (outputfile, leading_dot, low0 + 1,
156075f6d617Schristos 		      D_NUMLINES (b, mapping[FILE1]));
156175f6d617Schristos 	}
156275f6d617Schristos       else if (D_NUMLINES (b, mapping[FILE2]) == 0)
156375f6d617Schristos 	/* Write out a delete */
156475f6d617Schristos 	{
156575f6d617Schristos 	  if (low0 == high0)
156675f6d617Schristos 	    fprintf (outputfile, "%ldd\n", low0);
156775f6d617Schristos 	  else
156875f6d617Schristos 	    fprintf (outputfile, "%ld,%ldd\n", low0, high0);
156975f6d617Schristos 	}
157075f6d617Schristos       else
157175f6d617Schristos 	/* Write out an add or change */
157275f6d617Schristos 	{
157375f6d617Schristos 	  switch (high0 - low0)
157475f6d617Schristos 	    {
157575f6d617Schristos 	    case -1:
157675f6d617Schristos 	      fprintf (outputfile, "%lda\n", high0);
157775f6d617Schristos 	      break;
157875f6d617Schristos 	    case 0:
157975f6d617Schristos 	      fprintf (outputfile, "%ldc\n", high0);
158075f6d617Schristos 	      break;
158175f6d617Schristos 	    default:
158275f6d617Schristos 	      fprintf (outputfile, "%ld,%ldc\n", low0, high0);
158375f6d617Schristos 	      break;
158475f6d617Schristos 	    }
158575f6d617Schristos 
158675f6d617Schristos 	  undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]),
158775f6d617Schristos 		      low0, D_NUMLINES (b, mapping[FILE2]));
158875f6d617Schristos 	}
158975f6d617Schristos     }
159075f6d617Schristos   if (finalwrite) fprintf (outputfile, "w\nq\n");
159175f6d617Schristos   return conflicts_found;
159275f6d617Schristos }
159375f6d617Schristos 
159475f6d617Schristos /*
159575f6d617Schristos  * Read from INFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF
159675f6d617Schristos  * as a merged file.  This acts like 'ed file0 <[output_diff3_edscript]',
159775f6d617Schristos  * except that it works even for binary data or incomplete lines.
159875f6d617Schristos  *
159975f6d617Schristos  * As before, MAPPING maps from arg list file number to diff file number,
160075f6d617Schristos  * REV_MAPPING is its inverse,
160175f6d617Schristos  * and FILE0, FILE1, and FILE2 are the names of the files.
160275f6d617Schristos  *
160375f6d617Schristos  * Returns 1 if conflicts were found.
160475f6d617Schristos  */
160575f6d617Schristos 
160675f6d617Schristos static bool
output_diff3_merge(FILE * infile,FILE * outputfile,struct diff3_block * diff,int const mapping[3],int const rev_mapping[3],char const * file0,char const * file1,char const * file2)160775f6d617Schristos output_diff3_merge (FILE *infile, FILE *outputfile, struct diff3_block *diff,
160875f6d617Schristos 		    int const mapping[3], int const rev_mapping[3],
160975f6d617Schristos 		    char const *file0, char const *file1, char const *file2)
161075f6d617Schristos {
161175f6d617Schristos   int c;
161275f6d617Schristos   lin i;
161375f6d617Schristos   bool conflicts_found = 0, conflict;
161475f6d617Schristos   struct diff3_block *b;
161575f6d617Schristos   lin linesread = 0;
161675f6d617Schristos 
161775f6d617Schristos   for (b = diff; b; b = b->next)
161875f6d617Schristos     {
161975f6d617Schristos       /* Must do mapping correctly.  */
162075f6d617Schristos       enum diff_type type
162175f6d617Schristos 	= ((b->correspond == DIFF_ALL)
162275f6d617Schristos 	   ? DIFF_ALL
162375f6d617Schristos 	   : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
162475f6d617Schristos       char const *format_2nd = "<<<<<<< %s\n";
162575f6d617Schristos 
162675f6d617Schristos       /* If we aren't supposed to do this output block, skip it.  */
162775f6d617Schristos       switch (type)
162875f6d617Schristos 	{
162975f6d617Schristos 	default: continue;
163075f6d617Schristos 	case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
163175f6d617Schristos 	case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
163275f6d617Schristos 	case DIFF_ALL: if (simple_only) continue; conflict = flagging;
163375f6d617Schristos 	  format_2nd = "||||||| %s\n";
163475f6d617Schristos 	  break;
163575f6d617Schristos 	}
163675f6d617Schristos 
163775f6d617Schristos       /* Copy I lines from file 0.  */
163875f6d617Schristos       i = D_LOWLINE (b, FILE0) - linesread - 1;
163975f6d617Schristos       linesread += i;
164075f6d617Schristos       while (0 <= --i)
164175f6d617Schristos 	do
164275f6d617Schristos 	  {
164375f6d617Schristos 	    c = getc (infile);
164475f6d617Schristos 	    if (c == EOF)
164575f6d617Schristos 	      {
164675f6d617Schristos 		if (ferror (infile))
164775f6d617Schristos 		  perror_with_exit (_("read failed"));
164875f6d617Schristos 		else if (feof (infile))
164975f6d617Schristos 		  fatal ("input file shrank");
165075f6d617Schristos 	      }
165175f6d617Schristos 	    putc (c, outputfile);
165275f6d617Schristos 	  }
165375f6d617Schristos 	while (c != '\n');
165475f6d617Schristos 
165575f6d617Schristos       if (conflict)
165675f6d617Schristos 	{
165775f6d617Schristos 	  conflicts_found = 1;
165875f6d617Schristos 
165975f6d617Schristos 	  if (type == DIFF_ALL)
166075f6d617Schristos 	    {
166175f6d617Schristos 	      /* Put in lines from FILE0 with bracket.  */
166275f6d617Schristos 	      fprintf (outputfile, "<<<<<<< %s\n", file0);
166375f6d617Schristos 	      for (i = 0;
166475f6d617Schristos 		   i < D_NUMLINES (b, mapping[FILE0]);
166575f6d617Schristos 		   i++)
166675f6d617Schristos 		fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
166775f6d617Schristos 			D_RELLEN (b, mapping[FILE0], i), outputfile);
166875f6d617Schristos 	    }
166975f6d617Schristos 
167075f6d617Schristos 	  if (show_2nd)
167175f6d617Schristos 	    {
167275f6d617Schristos 	      /* Put in lines from FILE1 with bracket.  */
167375f6d617Schristos 	      fprintf (outputfile, format_2nd, file1);
167475f6d617Schristos 	      for (i = 0;
167575f6d617Schristos 		   i < D_NUMLINES (b, mapping[FILE1]);
167675f6d617Schristos 		   i++)
167775f6d617Schristos 		fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char),
167875f6d617Schristos 			D_RELLEN (b, mapping[FILE1], i), outputfile);
167975f6d617Schristos 	    }
168075f6d617Schristos 
168175f6d617Schristos 	  fprintf (outputfile, "=======\n");
168275f6d617Schristos 	}
168375f6d617Schristos 
168475f6d617Schristos       /* Put in lines from FILE2.  */
168575f6d617Schristos       for (i = 0;
168675f6d617Schristos 	   i < D_NUMLINES (b, mapping[FILE2]);
168775f6d617Schristos 	   i++)
168875f6d617Schristos 	fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
168975f6d617Schristos 		D_RELLEN (b, mapping[FILE2], i), outputfile);
169075f6d617Schristos 
169175f6d617Schristos       if (conflict)
169275f6d617Schristos 	fprintf (outputfile, ">>>>>>> %s\n", file2);
169375f6d617Schristos 
169475f6d617Schristos       /* Skip I lines in file 0.  */
169575f6d617Schristos       i = D_NUMLINES (b, FILE0);
169675f6d617Schristos       linesread += i;
169775f6d617Schristos       while (0 <= --i)
169875f6d617Schristos 	while ((c = getc (infile)) != '\n')
169975f6d617Schristos 	  if (c == EOF)
170075f6d617Schristos 	    {
170175f6d617Schristos 	      if (ferror (infile))
170275f6d617Schristos 		perror_with_exit (_("read failed"));
170375f6d617Schristos 	      else if (feof (infile))
170475f6d617Schristos 		{
170575f6d617Schristos 		  if (i || b->next)
170675f6d617Schristos 		    fatal ("input file shrank");
170775f6d617Schristos 		  return conflicts_found;
170875f6d617Schristos 		}
170975f6d617Schristos 	    }
171075f6d617Schristos     }
171175f6d617Schristos   /* Copy rest of common file.  */
171275f6d617Schristos   while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
171375f6d617Schristos     putc (c, outputfile);
171475f6d617Schristos   return conflicts_found;
171575f6d617Schristos }
171675f6d617Schristos 
171775f6d617Schristos /*
171875f6d617Schristos  * Reverse the order of the list of diff3 blocks.
171975f6d617Schristos  */
172075f6d617Schristos static struct diff3_block *
reverse_diff3_blocklist(struct diff3_block * diff)172175f6d617Schristos reverse_diff3_blocklist (struct diff3_block *diff)
172275f6d617Schristos {
172375f6d617Schristos   register struct diff3_block *tmp, *next, *prev;
172475f6d617Schristos 
172575f6d617Schristos   for (tmp = diff, prev = 0;  tmp;  tmp = next)
172675f6d617Schristos     {
172775f6d617Schristos       next = tmp->next;
172875f6d617Schristos       tmp->next = prev;
172975f6d617Schristos       prev = tmp;
173075f6d617Schristos     }
173175f6d617Schristos 
173275f6d617Schristos   return prev;
173375f6d617Schristos }
173475f6d617Schristos 
173575f6d617Schristos static void
fatal(char const * msgid)173675f6d617Schristos fatal (char const *msgid)
173775f6d617Schristos {
173875f6d617Schristos   error (EXIT_TROUBLE, 0, "%s", _(msgid));
173975f6d617Schristos   abort ();
174075f6d617Schristos }
174175f6d617Schristos 
174275f6d617Schristos static void
perror_with_exit(char const * string)174375f6d617Schristos perror_with_exit (char const *string)
174475f6d617Schristos {
174575f6d617Schristos   error (EXIT_TROUBLE, errno, "%s", string);
174675f6d617Schristos   abort ();
174775f6d617Schristos }
1748