Blame src/diff3.c

Packit 33f14e
/* diff3 - compare three files line by line
Packit 33f14e
Packit 33f14e
   Copyright (C) 1988-1989, 1992-1996, 1998, 2001-2002, 2004, 2006, 2009-2013,
Packit 33f14e
   2015-2017 Free Software Foundation, Inc.
Packit 33f14e
Packit 33f14e
   This program is free software: you can redistribute it and/or modify
Packit 33f14e
   it under the terms of the GNU General Public License as published by
Packit 33f14e
   the Free Software Foundation, either version 3 of the License, or
Packit 33f14e
   (at your option) any later version.
Packit 33f14e
Packit 33f14e
   This program is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 33f14e
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 33f14e
   GNU General Public License for more details.
Packit 33f14e
Packit 33f14e
   You should have received a copy of the GNU General Public License
Packit 33f14e
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 33f14e

Packit 33f14e
#include "system.h"
Packit 33f14e
#include "paths.h"
Packit 33f14e
Packit 33f14e
#include <stdio.h>
Packit 33f14e
#include <unlocked-io.h>
Packit 33f14e
Packit 33f14e
#include <c-stack.h>
Packit 33f14e
#include <cmpbuf.h>
Packit 33f14e
#include "die.h"
Packit 33f14e
#include <error.h>
Packit 33f14e
#include <exitfail.h>
Packit 33f14e
#include <file-type.h>
Packit 33f14e
#include <getopt.h>
Packit 33f14e
#include <progname.h>
Packit 33f14e
#include <system-quote.h>
Packit 33f14e
#include <version-etc.h>
Packit 33f14e
#include <xalloc.h>
Packit 33f14e
#include <xfreopen.h>
Packit 33f14e
Packit 33f14e
/* The official name of this program (e.g., no 'g' prefix).  */
Packit 33f14e
#define PROGRAM_NAME "diff3"
Packit 33f14e
Packit 33f14e
#define AUTHORS \
Packit 33f14e
  proper_name ("Randy Smith")
Packit 33f14e
Packit 33f14e
/* Internal data structures and macros for the diff3 program; includes
Packit 33f14e
   data structures for both diff3 diffs and normal diffs.  */
Packit 33f14e
Packit 33f14e
/* Different files within a three way diff.  */
Packit 33f14e
#define	FILE0	0
Packit 33f14e
#define	FILE1	1
Packit 33f14e
#define	FILE2	2
Packit 33f14e
Packit 33f14e
/* A three way diff is built from two two-way diffs; the file which
Packit 33f14e
   the two two-way diffs share is:  */
Packit 33f14e
#define	FILEC	FILE2
Packit 33f14e
Packit 33f14e
/* Different files within a two way diff.
Packit 33f14e
   FC is the common file, FO the other file.  */
Packit 33f14e
#define FO 0
Packit 33f14e
#define FC 1
Packit 33f14e
Packit 33f14e
/* The ranges are indexed by */
Packit 33f14e
#define	RANGE_START	0
Packit 33f14e
#define	RANGE_END	1
Packit 33f14e
Packit 33f14e
enum diff_type {
Packit 33f14e
  ERROR,			/* Should not be used */
Packit 33f14e
  ADD,				/* Two way diff add */
Packit 33f14e
  CHANGE,			/* Two way diff change */
Packit 33f14e
  DELETE,			/* Two way diff delete */
Packit 33f14e
  DIFF_ALL,			/* All three are different */
Packit 33f14e
  DIFF_1ST,			/* Only the first is different */
Packit 33f14e
  DIFF_2ND,			/* Only the second */
Packit 33f14e
  DIFF_3RD			/* Only the third */
Packit 33f14e
};
Packit 33f14e
Packit 33f14e
/* Two way diff */
Packit 33f14e
struct diff_block {
Packit 33f14e
  lin ranges[2][2];		/* Ranges are inclusive */
Packit 33f14e
  char **lines[2];		/* The actual lines (may contain nulls) */
Packit 33f14e
  size_t *lengths[2];		/* Line lengths (including newlines, if any) */
Packit 33f14e
  struct diff_block *next;
Packit 33f14e
#ifdef lint
Packit 33f14e
  struct diff_block *n2;	/* Used only when freeing.  */
Packit 33f14e
#endif
Packit 33f14e
};
Packit 33f14e
Packit 33f14e
/* Three way diff */
Packit 33f14e
Packit 33f14e
struct diff3_block {
Packit 33f14e
  enum diff_type correspond;	/* Type of diff */
Packit 33f14e
  lin ranges[3][2];		/* Ranges are inclusive */
Packit 33f14e
  char **lines[3];		/* The actual lines (may contain nulls) */
Packit 33f14e
  size_t *lengths[3];		/* Line lengths (including newlines, if any) */
Packit 33f14e
  struct diff3_block *next;
Packit 33f14e
};
Packit 33f14e
Packit 33f14e
/* Access the ranges on a diff block.  */
Packit 33f14e
#define	D_LOWLINE(diff, filenum)	\
Packit 33f14e
  ((diff)->ranges[filenum][RANGE_START])
Packit 33f14e
#define	D_HIGHLINE(diff, filenum)	\
Packit 33f14e
  ((diff)->ranges[filenum][RANGE_END])
Packit 33f14e
#define	D_NUMLINES(diff, filenum)	\
Packit 33f14e
  (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
Packit 33f14e
Packit 33f14e
/* Access the line numbers in a file in a diff by relative line
Packit 33f14e
   numbers (i.e. line number within the diff itself).  Note that these
Packit 33f14e
   are lvalues and can be used for assignment.  */
Packit 33f14e
#define	D_RELNUM(diff, filenum, linenum)	\
Packit 33f14e
  ((diff)->lines[filenum][linenum])
Packit 33f14e
#define	D_RELLEN(diff, filenum, linenum)	\
Packit 33f14e
  ((diff)->lengths[filenum][linenum])
Packit 33f14e
Packit 33f14e
/* And get at them directly, when that should be necessary.  */
Packit 33f14e
#define	D_LINEARRAY(diff, filenum)	\
Packit 33f14e
  ((diff)->lines[filenum])
Packit 33f14e
#define	D_LENARRAY(diff, filenum)	\
Packit 33f14e
  ((diff)->lengths[filenum])
Packit 33f14e
Packit 33f14e
/* Next block.  */
Packit 33f14e
#define	D_NEXT(diff)	((diff)->next)
Packit 33f14e
Packit 33f14e
/* Access the type of a diff3 block.  */
Packit 33f14e
#define	D3_TYPE(diff)	((diff)->correspond)
Packit 33f14e
Packit 33f14e
/* Line mappings based on diffs.  The first maps off the top of the
Packit 33f14e
   diff, the second off of the bottom.  */
Packit 33f14e
#define	D_HIGH_MAPLINE(diff, fromfile, tofile, linenum)	\
Packit 33f14e
  ((linenum)						\
Packit 33f14e
   - D_HIGHLINE ((diff), (fromfile))			\
Packit 33f14e
   + D_HIGHLINE ((diff), (tofile)))
Packit 33f14e
Packit 33f14e
#define	D_LOW_MAPLINE(diff, fromfile, tofile, linenum)	\
Packit 33f14e
  ((linenum)						\
Packit 33f14e
   - D_LOWLINE ((diff), (fromfile))			\
Packit 33f14e
   + D_LOWLINE ((diff), (tofile)))
Packit 33f14e

Packit 33f14e
/* Options variables for flags set on command line.  */
Packit 33f14e
Packit 33f14e
/* If nonzero, treat all files as text files, never as binary.  */
Packit 33f14e
static bool text;
Packit 33f14e
Packit 33f14e
/* Remove trailing carriage returns from input.  */
Packit 33f14e
static bool strip_trailing_cr;
Packit 33f14e
Packit 33f14e
/* If nonzero, write out an ed script instead of the standard diff3 format.  */
Packit 33f14e
static bool edscript;
Packit 33f14e
Packit 33f14e
/* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
Packit 33f14e
   preserve the lines which would normally be deleted from
Packit 33f14e
   file 1 with a special flagging mechanism.  */
Packit 33f14e
static bool flagging;
Packit 33f14e
Packit 33f14e
/* Use a tab to align output lines (-T).  */
Packit 33f14e
static bool initial_tab;
Packit 33f14e
Packit 33f14e
/* If nonzero, do not output information for overlapping diffs.  */
Packit 33f14e
static bool simple_only;
Packit 33f14e
Packit 33f14e
/* If nonzero, do not output information for non-overlapping diffs.  */
Packit 33f14e
static bool overlap_only;
Packit 33f14e
Packit 33f14e
/* If nonzero, show information for DIFF_2ND diffs.  */
Packit 33f14e
static bool show_2nd;
Packit 33f14e
Packit 33f14e
/* If nonzero, include ':wq' at the end of the script
Packit 33f14e
   to write out the file being edited.   */
Packit 33f14e
static bool finalwrite;
Packit 33f14e
Packit 33f14e
/* If nonzero, output a merged file.  */
Packit 33f14e
static bool merge;
Packit 33f14e
Packit 33f14e
static char *read_diff (char const *, char const *, char **);
Packit 33f14e
static char *scan_diff_line (char *, char **, size_t *, char *, char);
Packit 33f14e
static enum diff_type process_diff_control (char **, struct diff_block *);
Packit 33f14e
static bool compare_line_list (char * const[], size_t const[], char * const[], size_t const[], lin);
Packit 33f14e
static bool copy_stringlist (char * const[], size_t const[], char *[], size_t[], lin);
Packit 33f14e
static bool output_diff3_edscript (FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
Packit 33f14e
static bool output_diff3_merge (FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
Packit 33f14e
static struct diff3_block *create_diff3_block (lin, lin, lin, lin, lin, lin);
Packit 33f14e
static struct diff3_block *make_3way_diff (struct diff_block *, struct diff_block *);
Packit 33f14e
static struct diff3_block *reverse_diff3_blocklist (struct diff3_block *);
Packit 33f14e
static struct diff3_block *using_to_diff3_block (struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *);
Packit 33f14e
static struct diff_block *process_diff (char const *, char const *, struct diff_block **, char **);
Packit 33f14e
static void check_stdout (void);
Packit 33f14e
static void fatal (char const *) __attribute__((noreturn));
Packit 33f14e
static void output_diff3 (FILE *, struct diff3_block *, int const[3], int const[3]);
Packit 33f14e
static void perror_with_exit (char const *) __attribute__((noreturn));
Packit 33f14e
static void try_help (char const *, char const *) __attribute__((noreturn));
Packit 33f14e
static void usage (void);
Packit 33f14e
Packit 33f14e
static char const *diff_program = DEFAULT_DIFF_PROGRAM;
Packit 33f14e
Packit 33f14e
/* Values for long options that do not have single-letter equivalents.  */
Packit 33f14e
enum
Packit 33f14e
{
Packit 33f14e
  DIFF_PROGRAM_OPTION = CHAR_MAX + 1,
Packit 33f14e
  HELP_OPTION,
Packit 33f14e
  STRIP_TRAILING_CR_OPTION
Packit 33f14e
};
Packit 33f14e
Packit 33f14e
static struct option const longopts[] =
Packit 33f14e
{
Packit 33f14e
  {"diff-program", 1, 0, DIFF_PROGRAM_OPTION},
Packit 33f14e
  {"easy-only", 0, 0, '3'},
Packit 33f14e
  {"ed", 0, 0, 'e'},
Packit 33f14e
  {"help", 0, 0, HELP_OPTION},
Packit 33f14e
  {"initial-tab", 0, 0, 'T'},
Packit 33f14e
  {"label", 1, 0, 'L'},
Packit 33f14e
  {"merge", 0, 0, 'm'},
Packit 33f14e
  {"overlap-only", 0, 0, 'x'},
Packit 33f14e
  {"show-all", 0, 0, 'A'},
Packit 33f14e
  {"show-overlap", 0, 0, 'E'},
Packit 33f14e
  {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},
Packit 33f14e
  {"text", 0, 0, 'a'},
Packit 33f14e
  {"version", 0, 0, 'v'},
Packit 33f14e
  {0, 0, 0, 0}
Packit 33f14e
};
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
free_diff_block (struct diff_block *p)
Packit 33f14e
{
Packit 33f14e
#ifndef lint
Packit 33f14e
  (void)p;
Packit 33f14e
#else
Packit 33f14e
  while (p)
Packit 33f14e
    {
Packit 33f14e
      free (p->lines[0]);
Packit 33f14e
      free (p->lines[1]);
Packit 33f14e
      free (p->lengths[0]);
Packit 33f14e
      free (p->lengths[1]);
Packit 33f14e
      struct diff_block *next = p->n2;
Packit 33f14e
      free (p);
Packit 33f14e
      p = next;
Packit 33f14e
    }
Packit 33f14e
#endif
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Copy each next pointer to n2, since make_3way_diff would clobber the former,
Packit 33f14e
   yet we will still need something to free these buffers.  */
Packit 33f14e
static void
Packit 33f14e
next_to_n2 (struct diff_block *p)
Packit 33f14e
{
Packit 33f14e
#ifndef lint
Packit 33f14e
  (void)p;
Packit 33f14e
#else
Packit 33f14e
  while (p)
Packit 33f14e
    p = p->n2 = p->next;
Packit 33f14e
#endif
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
main (int argc, char **argv)
Packit 33f14e
{
Packit 33f14e
  int c, i;
Packit 33f14e
  int common;
Packit 33f14e
  int mapping[3];
Packit 33f14e
  int rev_mapping[3];
Packit 33f14e
  int incompat = 0;
Packit 33f14e
  bool conflicts_found;
Packit 33f14e
  struct diff_block *thread0, *thread1, *last_block;
Packit 33f14e
  struct diff3_block *diff3;
Packit 33f14e
  int tag_count = 0;
Packit 33f14e
  char *tag_strings[3];
Packit 33f14e
  char *commonname;
Packit 33f14e
  char **file;
Packit 33f14e
  struct stat statb;
Packit 33f14e
Packit 33f14e
  exit_failure = EXIT_TROUBLE;
Packit 33f14e
  initialize_main (&argc, &argv);
Packit 33f14e
  set_program_name (argv[0]);
Packit 33f14e
  setlocale (LC_ALL, "");
Packit 33f14e
  bindtextdomain (PACKAGE, LOCALEDIR);
Packit 33f14e
  textdomain (PACKAGE);
Packit 33f14e
  c_stack_action (0);
Packit 33f14e
Packit 33f14e
  while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != -1)
Packit 33f14e
    {
Packit 33f14e
      switch (c)
Packit 33f14e
	{
Packit 33f14e
	case 'a':
Packit 33f14e
	  text = true;
Packit 33f14e
	  break;
Packit 33f14e
	case 'A':
Packit 33f14e
	  show_2nd = true;
Packit 33f14e
	  flagging = true;
Packit 33f14e
	  incompat++;
Packit 33f14e
	  break;
Packit 33f14e
	case 'x':
Packit 33f14e
	  overlap_only = true;
Packit 33f14e
	  incompat++;
Packit 33f14e
	  break;
Packit 33f14e
	case '3':
Packit 33f14e
	  simple_only = true;
Packit 33f14e
	  incompat++;
Packit 33f14e
	  break;
Packit 33f14e
	case 'i':
Packit 33f14e
	  finalwrite = true;
Packit 33f14e
	  break;
Packit 33f14e
	case 'm':
Packit 33f14e
	  merge = true;
Packit 33f14e
	  break;
Packit 33f14e
	case 'X':
Packit 33f14e
	  overlap_only = true;
Packit 33f14e
	  FALLTHROUGH;
Packit 33f14e
	case 'E':
Packit 33f14e
	  flagging = true;
Packit 33f14e
	  FALLTHROUGH;
Packit 33f14e
	case 'e':
Packit 33f14e
	  incompat++;
Packit 33f14e
	  break;
Packit 33f14e
	case 'T':
Packit 33f14e
	  initial_tab = true;
Packit 33f14e
	  break;
Packit 33f14e
	case STRIP_TRAILING_CR_OPTION:
Packit 33f14e
	  strip_trailing_cr = true;
Packit 33f14e
	  break;
Packit 33f14e
	case 'v':
Packit 33f14e
	  version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version,
Packit 33f14e
		       AUTHORS, (char *) NULL);
Packit 33f14e
	  check_stdout ();
Packit 33f14e
	  return EXIT_SUCCESS;
Packit 33f14e
	case DIFF_PROGRAM_OPTION:
Packit 33f14e
	  diff_program = optarg;
Packit 33f14e
	  break;
Packit 33f14e
	case HELP_OPTION:
Packit 33f14e
	  usage ();
Packit 33f14e
	  check_stdout ();
Packit 33f14e
	  return EXIT_SUCCESS;
Packit 33f14e
	case 'L':
Packit 33f14e
	  /* Handle up to three -L options.  */
Packit 33f14e
	  if (tag_count < 3)
Packit 33f14e
	    {
Packit 33f14e
	      tag_strings[tag_count++] = optarg;
Packit 33f14e
	      break;
Packit 33f14e
	    }
Packit 33f14e
	  try_help ("too many file label options", 0);
Packit 33f14e
	default:
Packit 33f14e
	  try_help (0, 0);
Packit 33f14e
	}
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* -AeExX3 without -m implies ed script.  */
Packit 33f14e
  edscript = incompat & ~(int) merge;
Packit 33f14e
Packit 33f14e
  show_2nd |= ~incompat & merge;  /* -m without -AeExX3 implies -A.  */
Packit 33f14e
  flagging |= ~incompat & merge;
Packit 33f14e
Packit 33f14e
  if (incompat > 1  /* Ensure at most one of -AeExX3.  */
Packit 33f14e
      || finalwrite & merge /* -i -m would rewrite input file.  */
Packit 33f14e
      || (tag_count && ! flagging)) /* -L requires one of -AEX.  */
Packit 33f14e
    try_help ("incompatible options", 0);
Packit 33f14e
Packit 33f14e
  if (argc - optind != 3)
Packit 33f14e
    {
Packit 33f14e
      if (argc - optind < 3)
Packit 33f14e
	try_help ("missing operand after '%s'", argv[argc - 1]);
Packit 33f14e
      else
Packit 33f14e
	try_help ("extra operand '%s'", argv[optind + 3]);
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  file = &argv[optind];
Packit 33f14e
Packit 33f14e
  for (i = tag_count; i < 3; i++)
Packit 33f14e
    tag_strings[i] = file[i];
Packit 33f14e
Packit 33f14e
  /* Always compare file1 to file2, even if file2 is "-".
Packit 33f14e
     This is needed for -mAeExX3.  Using the file0 as
Packit 33f14e
     the common file would produce wrong results, because if the
Packit 33f14e
     file0-file1 diffs didn't line up with the file0-file2 diffs
Packit 33f14e
     (which is entirely possible since we don't use diff's -n option),
Packit 33f14e
     diff3 might report phantom changes from file1 to file2.
Packit 33f14e
Packit 33f14e
     Also, try to compare file0 to file1, because this is where
Packit 33f14e
     changes are expected to come from.  Diffing between these pairs
Packit 33f14e
     of files is more likely to avoid phantom changes from file0 to file1.
Packit 33f14e
Packit 33f14e
     Historically, the default common file was file2, so some older
Packit 33f14e
     applications (e.g. Emacs ediff) used file2 as the ancestor.  So,
Packit 33f14e
     for compatibility, if this is a 3-way diff (not a merge or
Packit 33f14e
     edscript), prefer file2 as the common file.  */
Packit 33f14e
Packit 33f14e
  common = 2 - (edscript | merge);
Packit 33f14e
Packit 33f14e
  if (STREQ (file[common], "-"))
Packit 33f14e
    {
Packit 33f14e
      /* Sigh.  We've got standard input as the common file.  We can't
Packit 33f14e
	 call diff twice on stdin.  Use the other arg as the common
Packit 33f14e
	 file instead.  */
Packit 33f14e
      common = 3 - common;
Packit 33f14e
      if (STREQ (file[0], "-") || STREQ (file[common], "-"))
Packit 33f14e
	fatal ("'-' specified for more than one input file");
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  mapping[0] = 0;
Packit 33f14e
  mapping[1] = 3 - common;
Packit 33f14e
  mapping[2] = common;
Packit 33f14e
Packit 33f14e
  for (i = 0; i < 3; i++)
Packit 33f14e
    rev_mapping[mapping[i]] = i;
Packit 33f14e
Packit 33f14e
  for (i = 0; i < 3; i++)
Packit 33f14e
    if (! STREQ (file[i], "-"))
Packit 33f14e
      {
Packit 33f14e
	if (stat (file[i], &statb) < 0)
Packit 33f14e
	  perror_with_exit (file[i]);
Packit 33f14e
	else if (S_ISDIR (statb.st_mode))
Packit 33f14e
	  die (EXIT_TROUBLE, EISDIR, "%s", file[i]);
Packit 33f14e
      }
Packit 33f14e
Packit 33f14e
#ifdef SIGCHLD
Packit 33f14e
  /* System V fork+wait does not work if SIGCHLD is ignored.  */
Packit 33f14e
  signal (SIGCHLD, SIG_DFL);
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
  /* Invoke diff twice on two pairs of input files, combine the two
Packit 33f14e
     diffs, and output them.  */
Packit 33f14e
Packit 33f14e
  char *b0, *b1;
Packit 33f14e
  commonname = file[rev_mapping[FILEC]];
Packit 33f14e
  thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block, &b1;;
Packit 33f14e
  thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block, &b0;;
Packit 33f14e
Packit 33f14e
  next_to_n2 (thread0);
Packit 33f14e
  next_to_n2 (thread1);
Packit 33f14e
Packit 33f14e
  diff3 = make_3way_diff (thread0, thread1);
Packit 33f14e
Packit 33f14e
  free_diff_block (thread0);
Packit 33f14e
  free_diff_block (thread1);
Packit 33f14e
Packit 33f14e
  if (edscript)
Packit 33f14e
    conflicts_found
Packit 33f14e
      = output_diff3_edscript (stdout, diff3, mapping, rev_mapping,
Packit 33f14e
			       tag_strings[0], tag_strings[1], tag_strings[2]);
Packit 33f14e
  else if (merge)
Packit 33f14e
    {
Packit 33f14e
      xfreopen (file[rev_mapping[FILE0]], "r", stdin);
Packit 33f14e
      conflicts_found
Packit 33f14e
	= output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping,
Packit 33f14e
			      tag_strings[0], tag_strings[1], tag_strings[2]);
Packit 33f14e
      if (ferror (stdin))
Packit 33f14e
	fatal ("read failed");
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
      output_diff3 (stdout, diff3, mapping, rev_mapping);
Packit 33f14e
      conflicts_found = false;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  free (b0);
Packit 33f14e
  free (b1);
Packit 33f14e
  check_stdout ();
Packit 33f14e
  exit (conflicts_found);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
try_help (char const *reason_msgid, char const *operand)
Packit 33f14e
{
Packit 33f14e
  if (reason_msgid)
Packit 33f14e
    error (0, 0, _(reason_msgid), operand);
Packit 33f14e
  die (EXIT_TROUBLE, 0,
Packit 33f14e
	 _("Try '%s --help' for more information."), program_name);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
check_stdout (void)
Packit 33f14e
{
Packit 33f14e
  if (ferror (stdout))
Packit 33f14e
    fatal ("write failed");
Packit 33f14e
  else if (fclose (stdout) != 0)
Packit 33f14e
    perror_with_exit (_("standard output"));
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
static char const * const option_help_msgid[] = {
Packit 33f14e
  N_("-A, --show-all              output all changes, bracketing conflicts"),
Packit 33f14e
  "",
Packit 33f14e
  N_("-e, --ed                    output ed script incorporating changes\n"
Packit 33f14e
     "                                from OLDFILE to YOURFILE into MYFILE"),
Packit 33f14e
  N_("-E, --show-overlap          like -e, but bracket conflicts"),
Packit 33f14e
  N_("-3, --easy-only             like -e, but incorporate only nonoverlapping changes"),
Packit 33f14e
  N_("-x, --overlap-only          like -e, but incorporate only overlapping changes"),
Packit 33f14e
  N_("-X                          like -x, but bracket conflicts"),
Packit 33f14e
  N_("-i                          append 'w' and 'q' commands to ed scripts"),
Packit 33f14e
  "",
Packit 33f14e
  N_("-m, --merge                 output actual merged file, according to\n"
Packit 33f14e
     "                                -A if no other options are given"),
Packit 33f14e
  "",
Packit 33f14e
  N_("-a, --text                  treat all files as text"),
Packit 33f14e
  N_("    --strip-trailing-cr     strip trailing carriage return on input"),
Packit 33f14e
  N_("-T, --initial-tab           make tabs line up by prepending a tab"),
Packit 33f14e
  N_("    --diff-program=PROGRAM  use PROGRAM to compare files"),
Packit 33f14e
  N_("-L, --label=LABEL           use LABEL instead of file name\n"
Packit 33f14e
     "                                (can be repeated up to three times)"),
Packit 33f14e
  "",
Packit 33f14e
  N_("    --help                  display this help and exit"),
Packit 33f14e
  N_("-v, --version               output version information and exit"),
Packit 33f14e
  0
Packit 33f14e
};
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
usage (void)
Packit 33f14e
{
Packit 33f14e
  char const * const *p;
Packit 33f14e
Packit 33f14e
  printf (_("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n"),
Packit 33f14e
	  program_name);
Packit 33f14e
  printf ("%s\n\n", _("Compare three files line by line."));
Packit 33f14e
Packit 33f14e
  fputs (_("\
Packit 33f14e
Mandatory arguments to long options are mandatory for short options too.\n\
Packit 33f14e
"), stdout);
Packit 33f14e
  for (p = option_help_msgid;  *p;  p++)
Packit 33f14e
    if (**p)
Packit 33f14e
      printf ("  %s\n", _(*p));
Packit 33f14e
    else
Packit 33f14e
      putchar ('\n');
Packit 33f14e
  fputs (_("\n\
Packit 33f14e
The default output format is a somewhat human-readable representation of\n\
Packit 33f14e
the changes.\n\
Packit 33f14e
\n\
Packit 33f14e
The -e, -E, -x, -X (and corresponding long) options cause an ed script\n\
Packit 33f14e
to be output instead of the default.\n\
Packit 33f14e
\n\
Packit 33f14e
Finally, the -m (--merge) option causes diff3 to do the merge internally\n\
Packit 33f14e
and output the actual merged file.  For unusual input, this is more\n\
Packit 33f14e
robust than using ed.\n"), stdout);
Packit 33f14e
  printf ("\n%s\n%s\n",
Packit 33f14e
	  _("If a FILE is '-', read standard input."),
Packit 33f14e
	  _("Exit status is 0 if successful, 1 if conflicts, 2 if trouble."));
Packit 33f14e
  emit_bug_reporting_address ();
Packit 33f14e
}
Packit 33f14e

Packit 33f14e
/* Combine the two diffs together into one.
Packit 33f14e
   Here is the algorithm:
Packit 33f14e
Packit 33f14e
     File2 is shared in common between the two diffs.
Packit 33f14e
     Diff02 is the diff between 0 and 2.
Packit 33f14e
     Diff12 is the diff between 1 and 2.
Packit 33f14e
Packit 33f14e
	1) Find the range for the first block in File2.
Packit 33f14e
	    a) Take the lowest of the two ranges (in File2) in the two
Packit 33f14e
	       current blocks (one from each diff) as being the low
Packit 33f14e
	       water mark.  Assign the upper end of this block as
Packit 33f14e
	       being the high water mark and move the current block up
Packit 33f14e
	       one.  Mark the block just moved over as to be used.
Packit 33f14e
	    b) Check the next block in the diff that the high water
Packit 33f14e
	       mark is *not* from.
Packit 33f14e
Packit 33f14e
	       *If* the high water mark is above
Packit 33f14e
	       the low end of the range in that block,
Packit 33f14e
Packit 33f14e
		   mark that block as to be used and move the current
Packit 33f14e
		   block up.  Set the high water mark to the max of
Packit 33f14e
		   the high end of this block and the current.  Repeat b.
Packit 33f14e
Packit 33f14e
	 2) Find the corresponding ranges in File0 (from the blocks
Packit 33f14e
	    in diff02; line per line outside of diffs) and in File1.
Packit 33f14e
	    Create a diff3_block, reserving space as indicated by the ranges.
Packit 33f14e
Packit 33f14e
	 3) Copy all of the pointers for file2 in.  At least for now,
Packit 33f14e
	    do memcmp's between corresponding strings in the two diffs.
Packit 33f14e
Packit 33f14e
	 4) Copy all of the pointers for file0 and 1 in.  Get what is
Packit 33f14e
	    needed from file2 (when there isn't a diff block, it's
Packit 33f14e
	    identical to file2 within the range between diff blocks).
Packit 33f14e
Packit 33f14e
	 5) If the diff blocks used came from only one of the two
Packit 33f14e
	    strings of diffs, then that file (i.e. the one other than
Packit 33f14e
	    the common file in that diff) is the odd person out.  If
Packit 33f14e
	    diff blocks are used from both sets, check to see if files
Packit 33f14e
	    0 and 1 match:
Packit 33f14e
Packit 33f14e
		Same number of lines?  If so, do a set of memcmp's (if
Packit 33f14e
	    a memcmp matches; copy the pointer over; it'll be easier
Packit 33f14e
	    later during comparisons).  If they match, 0 & 1 are the
Packit 33f14e
	    same.  If not, all three different.
Packit 33f14e
Packit 33f14e
     Then do it again, until the blocks are exhausted.  */
Packit 33f14e
Packit 33f14e
Packit 33f14e
/* Make a three way diff (chain of diff3_block's) from two two way
Packit 33f14e
   diffs (chains of diff_block's).  Assume that each of the two diffs
Packit 33f14e
   passed are onto the same file (i.e. that each of the diffs were
Packit 33f14e
   made "to" the same file).  Return a three way diff pointer with
Packit 33f14e
   numbering FILE0 = the other file in diff02, FILE1 = the other file
Packit 33f14e
   in diff12, and FILEC = the common file.  */
Packit 33f14e
Packit 33f14e
static struct diff3_block *
Packit 33f14e
make_3way_diff (struct diff_block *thread0, struct diff_block *thread1)
Packit 33f14e
{
Packit 33f14e
  /* Work on the two diffs passed to it as threads.  Thread number 0
Packit 33f14e
     is diff02, thread number 1 is diff12.  USING is the base of the
Packit 33f14e
     list of blocks to be used to construct each block of the three
Packit 33f14e
     way diff; if no blocks from a particular thread are to be used,
Packit 33f14e
     that element of USING is 0.  LAST_USING contains the last
Packit 33f14e
     elements on each of the using lists.
Packit 33f14e
Packit 33f14e
     HIGH_WATER_MARK is the highest line number in the common file
Packit 33f14e
     described in any of the diffs in either of the USING lists.
Packit 33f14e
     HIGH_WATER_THREAD names the thread.  Similarly BASE_WATER_MARK
Packit 33f14e
     and BASE_WATER_THREAD describe the lowest line number in the
Packit 33f14e
     common file described in any of the diffs in either of the USING
Packit 33f14e
     lists.  HIGH_WATER_DIFF is the diff from which the
Packit 33f14e
     HIGH_WATER_MARK was taken.
Packit 33f14e
Packit 33f14e
     HIGH_WATER_DIFF should always be equal to
Packit 33f14e
     LAST_USING[HIGH_WATER_THREAD].  OTHER_DIFF is the next diff to
Packit 33f14e
     check for higher water, and should always be equal to
Packit 33f14e
     CURRENT[HIGH_WATER_THREAD ^ 1].  OTHER_THREAD is the thread in
Packit 33f14e
     which the OTHER_DIFF is, and hence should always be equal to
Packit 33f14e
     HIGH_WATER_THREAD ^ 1.
Packit 33f14e
Packit 33f14e
     LAST_DIFF is the last diff block produced by this routine, for
Packit 33f14e
     line correspondence purposes between that diff and the one
Packit 33f14e
     currently being worked on.  It is ZERO_DIFF before any blocks
Packit 33f14e
     have been created.  */
Packit 33f14e
Packit 33f14e
  struct diff_block *using[2];
Packit 33f14e
  struct diff_block *last_using[2];
Packit 33f14e
  struct diff_block *current[2];
Packit 33f14e
Packit 33f14e
  lin high_water_mark;
Packit 33f14e
Packit 33f14e
  int high_water_thread;
Packit 33f14e
  int base_water_thread;
Packit 33f14e
  int other_thread;
Packit 33f14e
Packit 33f14e
  struct diff_block *high_water_diff;
Packit 33f14e
  struct diff_block *other_diff;
Packit 33f14e
Packit 33f14e
  struct diff3_block *result;
Packit 33f14e
  struct diff3_block *tmpblock;
Packit 33f14e
  struct diff3_block **result_end;
Packit 33f14e
Packit 33f14e
  struct diff3_block const *last_diff3;
Packit 33f14e
Packit 33f14e
  static struct diff3_block const zero_diff3;
Packit 33f14e
Packit 33f14e
  /* Initialization */
Packit 33f14e
  result = 0;
Packit 33f14e
  result_end = &result;
Packit 33f14e
  current[0] = thread0; current[1] = thread1;
Packit 33f14e
  last_diff3 = &zero_diff3;
Packit 33f14e
Packit 33f14e
  /* Sniff up the threads until we reach the end */
Packit 33f14e
Packit 33f14e
  while (current[0] || current[1])
Packit 33f14e
    {
Packit 33f14e
      using[0] = using[1] = last_using[0] = last_using[1] = 0;
Packit 33f14e
Packit 33f14e
      /* Setup low and high water threads, diffs, and marks.  */
Packit 33f14e
      if (!current[0])
Packit 33f14e
	base_water_thread = 1;
Packit 33f14e
      else if (!current[1])
Packit 33f14e
	base_water_thread = 0;
Packit 33f14e
      else
Packit 33f14e
	base_water_thread =
Packit 33f14e
	  (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
Packit 33f14e
Packit 33f14e
      high_water_thread = base_water_thread;
Packit 33f14e
Packit 33f14e
      high_water_diff = current[high_water_thread];
Packit 33f14e
Packit 33f14e
      high_water_mark = D_HIGHLINE (high_water_diff, FC);
Packit 33f14e
Packit 33f14e
      /* Make the diff you just got info from into the using class */
Packit 33f14e
      using[high_water_thread]
Packit 33f14e
	= last_using[high_water_thread]
Packit 33f14e
	= high_water_diff;
Packit 33f14e
      current[high_water_thread] = high_water_diff->next;
Packit 33f14e
      last_using[high_water_thread]->next = 0;
Packit 33f14e
Packit 33f14e
      /* And mark the other diff */
Packit 33f14e
      other_thread = high_water_thread ^ 0x1;
Packit 33f14e
      other_diff = current[other_thread];
Packit 33f14e
Packit 33f14e
      /* Shuffle up the ladder, checking the other diff to see if it
Packit 33f14e
	 needs to be incorporated.  */
Packit 33f14e
      while (other_diff
Packit 33f14e
	     && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
Packit 33f14e
	{
Packit 33f14e
Packit 33f14e
	  /* Incorporate this diff into the using list.  Note that
Packit 33f14e
	     this doesn't take it off the current list */
Packit 33f14e
	  if (using[other_thread])
Packit 33f14e
	    last_using[other_thread]->next = other_diff;
Packit 33f14e
	  else
Packit 33f14e
	    using[other_thread] = other_diff;
Packit 33f14e
	  last_using[other_thread] = other_diff;
Packit 33f14e
Packit 33f14e
	  /* Take it off the current list.  Note that this following
Packit 33f14e
	     code assumes that other_diff enters it equal to
Packit 33f14e
	     current[high_water_thread ^ 0x1] */
Packit 33f14e
	  current[other_thread] = current[other_thread]->next;
Packit 33f14e
	  other_diff->next = 0;
Packit 33f14e
Packit 33f14e
	  /* Set the high_water stuff
Packit 33f14e
	     If this comparison is equal, then this is the last pass
Packit 33f14e
	     through this loop; since diff blocks within a given
Packit 33f14e
	     thread cannot overlap, the high_water_mark will be
Packit 33f14e
	     *below* the range_start of either of the next diffs.  */
Packit 33f14e
Packit 33f14e
	  if (high_water_mark < D_HIGHLINE (other_diff, FC))
Packit 33f14e
	    {
Packit 33f14e
	      high_water_thread ^= 1;
Packit 33f14e
	      high_water_mark = D_HIGHLINE (other_diff, FC);
Packit 33f14e
	    }
Packit 33f14e
Packit 33f14e
	  /* Set the other diff */
Packit 33f14e
	  other_thread = high_water_thread ^ 0x1;
Packit 33f14e
	  other_diff = current[other_thread];
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      /* The using lists contain a list of all of the blocks to be
Packit 33f14e
	 included in this diff3_block.  Create it.  */
Packit 33f14e
Packit 33f14e
      tmpblock = using_to_diff3_block (using, last_using,
Packit 33f14e
				       base_water_thread, high_water_thread,
Packit 33f14e
				       last_diff3);
Packit 33f14e
Packit 33f14e
      if (!tmpblock)
Packit 33f14e
	fatal ("internal error: screwup in format of diff blocks");
Packit 33f14e
Packit 33f14e
      /* Put it on the list.  */
Packit 33f14e
      *result_end = tmpblock;
Packit 33f14e
      result_end = &tmpblock->next;
Packit 33f14e
Packit 33f14e
      /* Set up corresponding lines correctly.  */
Packit 33f14e
      last_diff3 = tmpblock;
Packit 33f14e
    }
Packit 33f14e
  return result;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Take two lists of blocks (from two separate diff threads) and put
Packit 33f14e
   them together into one diff3 block.  Return a pointer to this diff3
Packit 33f14e
   block or 0 for failure.
Packit 33f14e
Packit 33f14e
   All arguments besides using are for the convenience of the routine;
Packit 33f14e
   they could be derived from the using array.  LAST_USING is a pair
Packit 33f14e
   of pointers to the last blocks in the using structure.  LOW_THREAD
Packit 33f14e
   and HIGH_THREAD tell which threads contain the lowest and highest
Packit 33f14e
   line numbers for File0.  LAST_DIFF3 contains the last diff produced
Packit 33f14e
   in the calling routine.  This is used for lines mappings that
Packit 33f14e
   would still be identical to the state that diff ended in.
Packit 33f14e
Packit 33f14e
   A distinction should be made in this routine between the two diffs
Packit 33f14e
   that are part of a normal two diff block, and the three diffs that
Packit 33f14e
   are part of a diff3_block.  */
Packit 33f14e
Packit 33f14e
static struct diff3_block *
Packit 33f14e
using_to_diff3_block (struct diff_block *using[2],
Packit 33f14e
		      struct diff_block *last_using[2],
Packit 33f14e
		      int low_thread, int high_thread,
Packit 33f14e
		      struct diff3_block const *last_diff3)
Packit 33f14e
{
Packit 33f14e
  lin low[2], high[2];
Packit 33f14e
  struct diff3_block *result;
Packit 33f14e
  struct diff_block *ptr;
Packit 33f14e
  int d;
Packit 33f14e
  lin i;
Packit 33f14e
Packit 33f14e
  /* Find the range in the common file.  */
Packit 33f14e
  lin lowc = D_LOWLINE (using[low_thread], FC);
Packit 33f14e
  lin highc = D_HIGHLINE (last_using[high_thread], FC);
Packit 33f14e
Packit 33f14e
  /* Find the ranges in the other files.
Packit 33f14e
     If using[d] is null, that means that the file to which that diff
Packit 33f14e
     refers is equivalent to the common file over this range.  */
Packit 33f14e
Packit 33f14e
  for (d = 0; d < 2; d++)
Packit 33f14e
    if (using[d])
Packit 33f14e
      {
Packit 33f14e
	low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
Packit 33f14e
	high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
Packit 33f14e
      }
Packit 33f14e
    else
Packit 33f14e
      {
Packit 33f14e
	low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
Packit 33f14e
	high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
Packit 33f14e
      }
Packit 33f14e
Packit 33f14e
  /* Create a block with the appropriate sizes */
Packit 33f14e
  result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
Packit 33f14e
Packit 33f14e
  /* Copy information for the common file.
Packit 33f14e
     Return with a zero if any of the compares failed.  */
Packit 33f14e
Packit 33f14e
  for (d = 0; d < 2; d++)
Packit 33f14e
    for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
Packit 33f14e
      {
Packit 33f14e
	lin result_offset = D_LOWLINE (ptr, FC) - lowc;
Packit 33f14e
Packit 33f14e
	if (!copy_stringlist (D_LINEARRAY (ptr, FC),
Packit 33f14e
			      D_LENARRAY (ptr, FC),
Packit 33f14e
			      D_LINEARRAY (result, FILEC) + result_offset,
Packit 33f14e
			      D_LENARRAY (result, FILEC) + result_offset,
Packit 33f14e
			      D_NUMLINES (ptr, FC)))
Packit 33f14e
	  return 0;
Packit 33f14e
      }
Packit 33f14e
Packit 33f14e
  /* Copy information for file d.  First deal with anything that might be
Packit 33f14e
     before the first diff.  */
Packit 33f14e
Packit 33f14e
  for (d = 0; d < 2; d++)
Packit 33f14e
    {
Packit 33f14e
      struct diff_block *u = using[d];
Packit 33f14e
      lin lo = low[d], hi = high[d];
Packit 33f14e
Packit 33f14e
      for (i = 0;
Packit 33f14e
	   i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
Packit 33f14e
	   i++)
Packit 33f14e
	{
Packit 33f14e
	  D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
Packit 33f14e
	  D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      for (ptr = u; ptr; ptr = D_NEXT (ptr))
Packit 33f14e
	{
Packit 33f14e
	  lin result_offset = D_LOWLINE (ptr, FO) - lo;
Packit 33f14e
	  lin linec;
Packit 33f14e
Packit 33f14e
	  if (!copy_stringlist (D_LINEARRAY (ptr, FO),
Packit 33f14e
				D_LENARRAY (ptr, FO),
Packit 33f14e
				D_LINEARRAY (result, FILE0 + d) + result_offset,
Packit 33f14e
				D_LENARRAY (result, FILE0 + d) + result_offset,
Packit 33f14e
				D_NUMLINES (ptr, FO)))
Packit 33f14e
	    return 0;
Packit 33f14e
Packit 33f14e
	  /* Catch the lines between here and the next diff */
Packit 33f14e
	  linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
Packit 33f14e
	  for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
Packit 33f14e
	       i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
Packit 33f14e
	       i++)
Packit 33f14e
	    {
Packit 33f14e
	      D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
Packit 33f14e
	      D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
Packit 33f14e
	      linec++;
Packit 33f14e
	    }
Packit 33f14e
	}
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* Set correspond */
Packit 33f14e
  if (!using[0])
Packit 33f14e
    D3_TYPE (result) = DIFF_2ND;
Packit 33f14e
  else if (!using[1])
Packit 33f14e
    D3_TYPE (result) = DIFF_1ST;
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
      lin nl0 = D_NUMLINES (result, FILE0);
Packit 33f14e
      lin nl1 = D_NUMLINES (result, FILE1);
Packit 33f14e
Packit 33f14e
      if (nl0 != nl1
Packit 33f14e
	  || !compare_line_list (D_LINEARRAY (result, FILE0),
Packit 33f14e
				 D_LENARRAY (result, FILE0),
Packit 33f14e
				 D_LINEARRAY (result, FILE1),
Packit 33f14e
				 D_LENARRAY (result, FILE1),
Packit 33f14e
				 nl0))
Packit 33f14e
	D3_TYPE (result) = DIFF_ALL;
Packit 33f14e
      else
Packit 33f14e
	D3_TYPE (result) = DIFF_3RD;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return result;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Copy pointers from a list of strings to a different list of
Packit 33f14e
   strings.  If a spot in the second list is already filled, make sure
Packit 33f14e
   that it is filled with the same string; if not, return false, the copy
Packit 33f14e
   incomplete.  Upon successful completion of the copy, return true.  */
Packit 33f14e
Packit 33f14e
static bool
Packit 33f14e
copy_stringlist (char * const fromptrs[], size_t const fromlengths[],
Packit 33f14e
		 char *toptrs[], size_t tolengths[],
Packit 33f14e
		 lin copynum)
Packit 33f14e
{
Packit 33f14e
  register char * const *f = fromptrs;
Packit 33f14e
  register char **t = toptrs;
Packit 33f14e
  register size_t const *fl = fromlengths;
Packit 33f14e
  register size_t *tl = tolengths;
Packit 33f14e
Packit 33f14e
  while (copynum--)
Packit 33f14e
    {
Packit 33f14e
      if (*t)
Packit 33f14e
	{
Packit 33f14e
	  if (*fl != *tl || memcmp (*f, *t, *fl) != 0)
Packit 33f14e
	    return false;
Packit 33f14e
	}
Packit 33f14e
      else
Packit 33f14e
	{
Packit 33f14e
	  *t = *f;
Packit 33f14e
	  *tl = *fl;
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      t++; f++; tl++; fl++;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return true;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Create a diff3_block, with ranges as specified in the arguments.
Packit 33f14e
   Allocate the arrays for the various pointers (and zero them) based
Packit 33f14e
   on the arguments passed.  Return the block as a result.  */
Packit 33f14e
Packit 33f14e
static struct diff3_block *
Packit 33f14e
create_diff3_block (lin low0, lin high0,
Packit 33f14e
		    lin low1, lin high1,
Packit 33f14e
		    lin low2, lin high2)
Packit 33f14e
{
Packit 33f14e
  struct diff3_block *result = xmalloc (sizeof *result);
Packit 33f14e
  lin numlines;
Packit 33f14e
Packit 33f14e
  D3_TYPE (result) = ERROR;
Packit 33f14e
  D_NEXT (result) = 0;
Packit 33f14e
Packit 33f14e
  /* Assign ranges */
Packit 33f14e
  D_LOWLINE (result, FILE0) = low0;
Packit 33f14e
  D_HIGHLINE (result, FILE0) = high0;
Packit 33f14e
  D_LOWLINE (result, FILE1) = low1;
Packit 33f14e
  D_HIGHLINE (result, FILE1) = high1;
Packit 33f14e
  D_LOWLINE (result, FILE2) = low2;
Packit 33f14e
  D_HIGHLINE (result, FILE2) = high2;
Packit 33f14e
Packit 33f14e
  /* Allocate and zero space */
Packit 33f14e
  numlines = D_NUMLINES (result, FILE0);
Packit 33f14e
  if (numlines)
Packit 33f14e
    {
Packit 33f14e
      D_LINEARRAY (result, FILE0) = xcalloc (numlines, sizeof (char *));
Packit 33f14e
      D_LENARRAY (result, FILE0) = xcalloc (numlines, sizeof (size_t));
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
      D_LINEARRAY (result, FILE0) = 0;
Packit 33f14e
      D_LENARRAY (result, FILE0) = 0;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  numlines = D_NUMLINES (result, FILE1);
Packit 33f14e
  if (numlines)
Packit 33f14e
    {
Packit 33f14e
      D_LINEARRAY (result, FILE1) = xcalloc (numlines, sizeof (char *));
Packit 33f14e
      D_LENARRAY (result, FILE1) = xcalloc (numlines, sizeof (size_t));
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
      D_LINEARRAY (result, FILE1) = 0;
Packit 33f14e
      D_LENARRAY (result, FILE1) = 0;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  numlines = D_NUMLINES (result, FILE2);
Packit 33f14e
  if (numlines)
Packit 33f14e
    {
Packit 33f14e
      D_LINEARRAY (result, FILE2) = xcalloc (numlines, sizeof (char *));
Packit 33f14e
      D_LENARRAY (result, FILE2) = xcalloc (numlines, sizeof (size_t));
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
      D_LINEARRAY (result, FILE2) = 0;
Packit 33f14e
      D_LENARRAY (result, FILE2) = 0;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* Return */
Packit 33f14e
  return result;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Compare two lists of lines of text.
Packit 33f14e
   Return 1 if they are equivalent, 0 if not.  */
Packit 33f14e
Packit 33f14e
static bool
Packit 33f14e
compare_line_list (char * const list1[], size_t const lengths1[],
Packit 33f14e
		   char * const list2[], size_t const lengths2[],
Packit 33f14e
		   lin nl)
Packit 33f14e
{
Packit 33f14e
  char * const *l1 = list1;
Packit 33f14e
  char * const *l2 = list2;
Packit 33f14e
  size_t const *lgths1 = lengths1;
Packit 33f14e
  size_t const *lgths2 = lengths2;
Packit 33f14e
Packit 33f14e
  while (nl--)
Packit 33f14e
    if (!*l1 || !*l2 || *lgths1 != *lgths2++
Packit 33f14e
	|| memcmp (*l1++, *l2++, *lgths1++) != 0)
Packit 33f14e
      return false;
Packit 33f14e
  return true;
Packit 33f14e
}
Packit 33f14e

Packit 33f14e
/* Input and parse two way diffs.  */
Packit 33f14e
Packit 33f14e
static struct diff_block *
Packit 33f14e
process_diff (char const *filea,
Packit 33f14e
	      char const *fileb,
Packit 33f14e
	      struct diff_block **last_block,
Packit 33f14e
	      char **buf_to_free)
Packit 33f14e
{
Packit 33f14e
  char *diff_contents;
Packit 33f14e
  char *diff_limit;
Packit 33f14e
  char *scan_diff;
Packit 33f14e
  enum diff_type dt;
Packit 33f14e
  lin i;
Packit 33f14e
  struct diff_block *block_list;
Packit 33f14e
  struct diff_block **block_list_end = &block_list;
Packit 33f14e
  struct diff_block *bptr IF_LINT (= NULL);
Packit 33f14e
  size_t too_many_lines = (PTRDIFF_MAX
Packit 33f14e
			   / MIN (sizeof *bptr->lines[1],
Packit 33f14e
				  sizeof *bptr->lengths[1]));
Packit 33f14e
Packit 33f14e
  diff_limit = read_diff (filea, fileb, &diff_contents);
Packit 33f14e
  *buf_to_free = diff_contents;
Packit 33f14e
  scan_diff = diff_contents;
Packit 33f14e
Packit 33f14e
  while (scan_diff < diff_limit)
Packit 33f14e
    {
Packit 33f14e
      bptr = xmalloc (sizeof *bptr);
Packit 33f14e
      bptr->lines[0] = bptr->lines[1] = 0;
Packit 33f14e
      bptr->lengths[0] = bptr->lengths[1] = 0;
Packit 33f14e
Packit 33f14e
      dt = process_diff_control (&scan_diff, bptr);
Packit 33f14e
      if (dt == ERROR || *scan_diff != '\n')
Packit 33f14e
	{
Packit 33f14e
	  fprintf (stderr, _("%s: diff failed: "), program_name);
Packit 33f14e
	  do
Packit 33f14e
	    {
Packit 33f14e
	      putc (*scan_diff, stderr);
Packit 33f14e
	    }
Packit 33f14e
	  while (*scan_diff++ != '\n');
Packit 33f14e
	  exit (EXIT_TROUBLE);
Packit 33f14e
	}
Packit 33f14e
      scan_diff++;
Packit 33f14e
Packit 33f14e
      /* Force appropriate ranges to be null, if necessary */
Packit 33f14e
      switch (dt)
Packit 33f14e
	{
Packit 33f14e
	case ADD:
Packit 33f14e
	  bptr->ranges[0][0]++;
Packit 33f14e
	  break;
Packit 33f14e
	case DELETE:
Packit 33f14e
	  bptr->ranges[1][0]++;
Packit 33f14e
	  break;
Packit 33f14e
	case CHANGE:
Packit 33f14e
	  break;
Packit 33f14e
	default:
Packit 33f14e
	  fatal ("internal error: invalid diff type in process_diff");
Packit 33f14e
	  break;
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      /* Allocate space for the pointers for the lines from filea, and
Packit 33f14e
	 parcel them out among these pointers */
Packit 33f14e
      if (dt != ADD)
Packit 33f14e
	{
Packit 33f14e
	  lin numlines = D_NUMLINES (bptr, 0);
Packit 33f14e
	  if (too_many_lines <= numlines)
Packit 33f14e
	    xalloc_die ();
Packit 33f14e
	  bptr->lines[0] = xmalloc (numlines * sizeof *bptr->lines[0]);
Packit 33f14e
	  bptr->lengths[0] = xmalloc (numlines * sizeof *bptr->lengths[0]);
Packit 33f14e
	  for (i = 0; i < numlines; i++)
Packit 33f14e
	    scan_diff = scan_diff_line (scan_diff,
Packit 33f14e
					&(bptr->lines[0][i]),
Packit 33f14e
					&(bptr->lengths[0][i]),
Packit 33f14e
					diff_limit,
Packit 33f14e
					'<');
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      /* Get past the separator for changes */
Packit 33f14e
      if (dt == CHANGE)
Packit 33f14e
	{
Packit 33f14e
	  if (strncmp (scan_diff, "---\n", 4))
Packit 33f14e
	    fatal ("invalid diff format; invalid change separator");
Packit 33f14e
	  scan_diff += 4;
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      /* Allocate space for the pointers for the lines from fileb, and
Packit 33f14e
	 parcel them out among these pointers */
Packit 33f14e
      if (dt != DELETE)
Packit 33f14e
	{
Packit 33f14e
	  lin numlines = D_NUMLINES (bptr, 1);
Packit 33f14e
	  if (too_many_lines <= numlines)
Packit 33f14e
	    xalloc_die ();
Packit 33f14e
	  bptr->lines[1] = xmalloc (numlines * sizeof *bptr->lines[1]);
Packit 33f14e
	  bptr->lengths[1] = xmalloc (numlines * sizeof *bptr->lengths[1]);
Packit 33f14e
	  for (i = 0; i < numlines; i++)
Packit 33f14e
	    scan_diff = scan_diff_line (scan_diff,
Packit 33f14e
					&(bptr->lines[1][i]),
Packit 33f14e
					&(bptr->lengths[1][i]),
Packit 33f14e
					diff_limit,
Packit 33f14e
					'>');
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      /* Place this block on the blocklist.  */
Packit 33f14e
      *block_list_end = bptr;
Packit 33f14e
      block_list_end = &bptr->next;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  *block_list_end = NULL;
Packit 33f14e
  *last_block = bptr;
Packit 33f14e
  return block_list;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Skip tabs and spaces, and return the first character after them.  */
Packit 33f14e
Packit 33f14e
static char * _GL_ATTRIBUTE_PURE
Packit 33f14e
skipwhite (char *s)
Packit 33f14e
{
Packit 33f14e
  while (*s == ' ' || *s == '\t')
Packit 33f14e
    s++;
Packit 33f14e
  return s;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Read a nonnegative line number from S, returning the address of the
Packit 33f14e
   first character after the line number, and storing the number into
Packit 33f14e
   *PNUM.  Return 0 if S does not point to a valid line number.  */
Packit 33f14e
Packit 33f14e
static char *
Packit 33f14e
readnum (char *s, lin *pnum)
Packit 33f14e
{
Packit 33f14e
  unsigned char c = *s;
Packit 33f14e
  lin num = 0;
Packit 33f14e
Packit 33f14e
  if (! ISDIGIT (c))
Packit 33f14e
    return 0;
Packit 33f14e
Packit 33f14e
  do
Packit 33f14e
    {
Packit 33f14e
      num = c - '0' + num * 10;
Packit 33f14e
      c = *++s;
Packit 33f14e
    }
Packit 33f14e
  while (ISDIGIT (c));
Packit 33f14e
Packit 33f14e
  *pnum = num;
Packit 33f14e
  return s;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Parse a normal format diff control string.  Return the type of the
Packit 33f14e
   diff (ERROR if the format is bad).  All of the other important
Packit 33f14e
   information is filled into to the structure pointed to by db, and
Packit 33f14e
   the string pointer (whose location is passed to this routine) is
Packit 33f14e
   updated to point beyond the end of the string parsed.  Note that
Packit 33f14e
   only the ranges in the diff_block will be set by this routine.
Packit 33f14e
Packit 33f14e
   If some specific pair of numbers has been reduced to a single
Packit 33f14e
   number, then both corresponding numbers in the diff block are set
Packit 33f14e
   to that number.  In general these numbers are interpreted as ranges
Packit 33f14e
   inclusive, unless being used by the ADD or DELETE commands.  It is
Packit 33f14e
   assumed that these will be special cased in a superior routine.   */
Packit 33f14e
Packit 33f14e
static enum diff_type
Packit 33f14e
process_diff_control (char **string, struct diff_block *db)
Packit 33f14e
{
Packit 33f14e
  char *s = *string;
Packit 33f14e
  enum diff_type type;
Packit 33f14e
Packit 33f14e
  /* Read first set of digits */
Packit 33f14e
  s = readnum (skipwhite (s), &db->ranges[0][RANGE_START]);
Packit 33f14e
  if (! s)
Packit 33f14e
    return ERROR;
Packit 33f14e
Packit 33f14e
  /* Was that the only digit? */
Packit 33f14e
  s = skipwhite (s);
Packit 33f14e
  if (*s == ',')
Packit 33f14e
    {
Packit 33f14e
      s = readnum (s + 1, &db->ranges[0][RANGE_END]);
Packit 33f14e
      if (! s)
Packit 33f14e
	return ERROR;
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    db->ranges[0][RANGE_END] = db->ranges[0][RANGE_START];
Packit 33f14e
Packit 33f14e
  /* Get the letter */
Packit 33f14e
  s = skipwhite (s);
Packit 33f14e
  switch (*s)
Packit 33f14e
    {
Packit 33f14e
    case 'a':
Packit 33f14e
      type = ADD;
Packit 33f14e
      break;
Packit 33f14e
    case 'c':
Packit 33f14e
      type = CHANGE;
Packit 33f14e
      break;
Packit 33f14e
    case 'd':
Packit 33f14e
      type = DELETE;
Packit 33f14e
      break;
Packit 33f14e
    default:
Packit 33f14e
      return ERROR;			/* Bad format */
Packit 33f14e
    }
Packit 33f14e
  s++;				/* Past letter */
Packit 33f14e
Packit 33f14e
  /* Read second set of digits */
Packit 33f14e
  s = readnum (skipwhite (s), &db->ranges[1][RANGE_START]);
Packit 33f14e
  if (! s)
Packit 33f14e
    return ERROR;
Packit 33f14e
Packit 33f14e
  /* Was that the only digit? */
Packit 33f14e
  s = skipwhite (s);
Packit 33f14e
  if (*s == ',')
Packit 33f14e
    {
Packit 33f14e
      s = readnum (s + 1, &db->ranges[1][RANGE_END]);
Packit 33f14e
      if (! s)
Packit 33f14e
	return ERROR;
Packit 33f14e
      s = skipwhite (s);		/* To move to end */
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    db->ranges[1][RANGE_END] = db->ranges[1][RANGE_START];
Packit 33f14e
Packit 33f14e
  *string = s;
Packit 33f14e
  return type;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
static char *
Packit 33f14e
read_diff (char const *filea,
Packit 33f14e
	   char const *fileb,
Packit 33f14e
	   char **output_placement)
Packit 33f14e
{
Packit 33f14e
  char *diff_result;
Packit 33f14e
  size_t current_chunk_size, total;
Packit 33f14e
  int fd, wstatus, status;
Packit 33f14e
  int werrno = 0;
Packit 33f14e
  struct stat pipestat;
Packit 33f14e
  char const *argv[9];
Packit 33f14e
  char const **ap;
Packit 33f14e
#if HAVE_WORKING_FORK
Packit 33f14e
  int fds[2];
Packit 33f14e
  pid_t pid;
Packit 33f14e
#else
Packit 33f14e
  FILE *fpipe;
Packit 33f14e
  char *command;
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
  ap = argv;
Packit 33f14e
  *ap++ = diff_program;
Packit 33f14e
  if (text)
Packit 33f14e
    *ap++ = "-a";
Packit 33f14e
  if (strip_trailing_cr)
Packit 33f14e
    *ap++ = "--strip-trailing-cr";
Packit 33f14e
  *ap++ = "--horizon-lines=100";
Packit 33f14e
  *ap++ = "--";
Packit 33f14e
  *ap++ = filea;
Packit 33f14e
  *ap++ = fileb;
Packit 33f14e
  *ap = 0;
Packit 33f14e
Packit 33f14e
#if HAVE_WORKING_FORK
Packit 33f14e
Packit 33f14e
  if (pipe (fds) != 0)
Packit 33f14e
    perror_with_exit ("pipe");
Packit 33f14e
Packit 33f14e
  pid = fork ();
Packit 33f14e
  if (pid == 0)
Packit 33f14e
    {
Packit 33f14e
      /* Child */
Packit 33f14e
      close (fds[0]);
Packit 33f14e
      if (fds[1] != STDOUT_FILENO)
Packit 33f14e
	{
Packit 33f14e
	  dup2 (fds[1], STDOUT_FILENO);
Packit 33f14e
	  close (fds[1]);
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      /* The cast to (char **) is needed for portability to older
Packit 33f14e
	 hosts with a nonstandard prototype for execvp.  */
Packit 33f14e
      execvp (diff_program, (char **) argv);
Packit 33f14e
Packit 33f14e
      _exit (errno == ENOENT ? 127 : 126);
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  if (pid == -1)
Packit 33f14e
    perror_with_exit ("fork");
Packit 33f14e
Packit 33f14e
  close (fds[1]);		/* Prevent erroneous lack of EOF */
Packit 33f14e
  fd = fds[0];
Packit 33f14e
Packit 33f14e
#else
Packit 33f14e
Packit 33f14e
  command = system_quote_argv (SCI_SYSTEM, (char **) argv);
Packit 33f14e
  errno = 0;
Packit 33f14e
  fpipe = popen (command, "r");
Packit 33f14e
  if (!fpipe)
Packit 33f14e
    perror_with_exit (command);
Packit 33f14e
  free (command);
Packit 33f14e
  fd = fileno (fpipe);
Packit 33f14e
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
  if (fstat (fd, &pipestat) != 0)
Packit 33f14e
    perror_with_exit ("fstat");
Packit 33f14e
  current_chunk_size = MAX (1, STAT_BLOCKSIZE (pipestat));
Packit 33f14e
  diff_result = xmalloc (current_chunk_size);
Packit 33f14e
  total = 0;
Packit 33f14e
Packit 33f14e
  for (;;)
Packit 33f14e
    {
Packit 33f14e
      size_t bytes_to_read = current_chunk_size - total;
Packit 33f14e
      size_t bytes = block_read (fd, diff_result + total, bytes_to_read);
Packit 33f14e
      total += bytes;
Packit 33f14e
      if (bytes != bytes_to_read)
Packit 33f14e
	{
Packit 33f14e
	  if (bytes == SIZE_MAX)
Packit 33f14e
	    perror_with_exit (_("read failed"));
Packit 33f14e
	  break;
Packit 33f14e
	}
Packit 33f14e
      if (PTRDIFF_MAX / 2 <= current_chunk_size)
Packit 33f14e
	xalloc_die ();
Packit 33f14e
      current_chunk_size *= 2;
Packit 33f14e
      diff_result = xrealloc (diff_result, current_chunk_size);
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  if (total != 0 && diff_result[total-1] != '\n')
Packit 33f14e
    fatal ("invalid diff format; incomplete last line");
Packit 33f14e
Packit 33f14e
  *output_placement = diff_result;
Packit 33f14e
Packit 33f14e
#if ! HAVE_WORKING_FORK
Packit 33f14e
Packit 33f14e
  wstatus = pclose (fpipe);
Packit 33f14e
  if (wstatus == -1)
Packit 33f14e
    werrno = errno;
Packit 33f14e
Packit 33f14e
#else
Packit 33f14e
Packit 33f14e
  if (close (fd) != 0)
Packit 33f14e
    perror_with_exit ("close");
Packit 33f14e
  if (waitpid (pid, &wstatus, 0) < 0)
Packit 33f14e
    perror_with_exit ("waitpid");
Packit 33f14e
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
  status = ! werrno && WIFEXITED (wstatus) ? WEXITSTATUS (wstatus) : INT_MAX;
Packit 33f14e
Packit 33f14e
  if (EXIT_TROUBLE <= status)
Packit 33f14e
    die (EXIT_TROUBLE, werrno,
Packit 33f14e
	   _(status == 126
Packit 33f14e
	     ? "subsidiary program '%s' could not be invoked"
Packit 33f14e
	     : status == 127
Packit 33f14e
	     ? "subsidiary program '%s' not found"
Packit 33f14e
	     : status == INT_MAX
Packit 33f14e
	     ? "subsidiary program '%s' failed"
Packit 33f14e
	     : "subsidiary program '%s' failed (exit status %d)"),
Packit 33f14e
	   diff_program, status);
Packit 33f14e
Packit 33f14e
  return diff_result + total;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
Packit 33f14e
/* Scan a regular diff line (consisting of > or <, followed by a
Packit 33f14e
   space, followed by text (including nulls) up to a newline.
Packit 33f14e
Packit 33f14e
   This next routine began life as a macro and many parameters in it
Packit 33f14e
   are used as call-by-reference values.  */
Packit 33f14e
static char *
Packit 33f14e
scan_diff_line (char *scan_ptr, char **set_start, size_t *set_length,
Packit 33f14e
		char *limit, char leadingchar)
Packit 33f14e
{
Packit 33f14e
  char *line_ptr;
Packit 33f14e
Packit 33f14e
  if (!(scan_ptr[0] == leadingchar
Packit 33f14e
	&& scan_ptr[1] == ' '))
Packit 33f14e
    fatal ("invalid diff format; incorrect leading line chars");
Packit 33f14e
Packit 33f14e
  *set_start = line_ptr = scan_ptr + 2;
Packit 33f14e
  while (*line_ptr++ != '\n')
Packit 33f14e
    continue;
Packit 33f14e
Packit 33f14e
  /* Include newline if the original line ended in a newline,
Packit 33f14e
     or if an edit script is being generated.
Packit 33f14e
     Copy any missing newline message to stderr if an edit script is being
Packit 33f14e
     generated, because edit scripts cannot handle missing newlines.
Packit 33f14e
     Return the beginning of the next line.  */
Packit 33f14e
  *set_length = line_ptr - *set_start;
Packit 33f14e
  if (line_ptr < limit && *line_ptr == '\\')
Packit 33f14e
    {
Packit 33f14e
      if (edscript)
Packit 33f14e
	fprintf (stderr, "%s:", program_name);
Packit 33f14e
      else
Packit 33f14e
	--*set_length;
Packit 33f14e
      line_ptr++;
Packit 33f14e
      do
Packit 33f14e
	{
Packit 33f14e
	  if (edscript)
Packit 33f14e
	    putc (*line_ptr, stderr);
Packit 33f14e
	}
Packit 33f14e
      while (*line_ptr++ != '\n');
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return line_ptr;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Output a three way diff passed as a list of diff3_block's.  The
Packit 33f14e
   argument MAPPING is indexed by external file number (in the
Packit 33f14e
   argument list) and contains the internal file number (from the diff
Packit 33f14e
   passed).  This is important because the user expects outputs in
Packit 33f14e
   terms of the argument list number, and the diff passed may have
Packit 33f14e
   been done slightly differently (if the last argument was "-", for
Packit 33f14e
   example).  REV_MAPPING is the inverse of MAPPING.  */
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
output_diff3 (FILE *outputfile, struct diff3_block *diff,
Packit 33f14e
	      int const mapping[3], int const rev_mapping[3])
Packit 33f14e
{
Packit 33f14e
  int i;
Packit 33f14e
  int oddoneout;
Packit 33f14e
  char *cp;
Packit 33f14e
  struct diff3_block *ptr;
Packit 33f14e
  lin line;
Packit 33f14e
  size_t length;
Packit 33f14e
  int dontprint;
Packit 33f14e
  static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
Packit 33f14e
  char const *line_prefix = initial_tab ? "\t" : "  ";
Packit 33f14e
Packit 33f14e
  for (ptr = diff; ptr; ptr = D_NEXT (ptr))
Packit 33f14e
    {
Packit 33f14e
      char x[2];
Packit 33f14e
Packit 33f14e
      switch (ptr->correspond)
Packit 33f14e
	{
Packit 33f14e
	case DIFF_ALL:
Packit 33f14e
	  x[0] = 0;
Packit 33f14e
	  dontprint = 3;	/* Print them all */
Packit 33f14e
	  oddoneout = 3;	/* Nobody's odder than anyone else */
Packit 33f14e
	  break;
Packit 33f14e
	case DIFF_1ST:
Packit 33f14e
	case DIFF_2ND:
Packit 33f14e
	case DIFF_3RD:
Packit 33f14e
	  oddoneout = rev_mapping[ptr->correspond - DIFF_1ST];
Packit 33f14e
Packit 33f14e
	  x[0] = oddoneout + '1';
Packit 33f14e
	  x[1] = 0;
Packit 33f14e
	  dontprint = oddoneout == 0;
Packit 33f14e
	  break;
Packit 33f14e
	default:
Packit 33f14e
	  fatal ("internal error: invalid diff type passed to output");
Packit 33f14e
	}
Packit 33f14e
      fprintf (outputfile, "====%s\n", x);
Packit 33f14e
Packit 33f14e
      /* Go 0, 2, 1 if the first and third outputs are equivalent.  */
Packit 33f14e
      for (i = 0; i < 3;
Packit 33f14e
	   i = (oddoneout == 1 ? skew_increment[i] : i + 1))
Packit 33f14e
	{
Packit 33f14e
	  int realfile = mapping[i];
Packit 33f14e
	  lin lowt = D_LOWLINE (ptr, realfile);
Packit 33f14e
	  lin hight = D_HIGHLINE (ptr, realfile);
Packit 33f14e
	  printint llowt = lowt;
Packit 33f14e
	  printint lhight = hight;
Packit 33f14e
Packit 33f14e
	  fprintf (outputfile, "%d:", i + 1);
Packit 33f14e
	  switch (lowt - hight)
Packit 33f14e
	    {
Packit 33f14e
	    case 1:
Packit 33f14e
	      fprintf (outputfile, "%"pI"da\n", llowt - 1);
Packit 33f14e
	      break;
Packit 33f14e
	    case 0:
Packit 33f14e
	      fprintf (outputfile, "%"pI"dc\n", llowt);
Packit 33f14e
	      break;
Packit 33f14e
	    default:
Packit 33f14e
	      fprintf (outputfile, "%"pI"d,%"pI"dc\n", llowt, lhight);
Packit 33f14e
	      break;
Packit 33f14e
	    }
Packit 33f14e
Packit 33f14e
	  if (i == dontprint) continue;
Packit 33f14e
Packit 33f14e
	  if (lowt <= hight)
Packit 33f14e
	    {
Packit 33f14e
	      line = 0;
Packit 33f14e
	      do
Packit 33f14e
		{
Packit 33f14e
		  fputs (line_prefix, outputfile);
Packit 33f14e
		  cp = D_RELNUM (ptr, realfile, line);
Packit 33f14e
		  length = D_RELLEN (ptr, realfile, line);
Packit 33f14e
		  fwrite (cp, sizeof (char), length, outputfile);
Packit 33f14e
		}
Packit 33f14e
	      while (++line < hight - lowt + 1);
Packit 33f14e
	      if (cp[length - 1] != '\n')
Packit 33f14e
		fprintf (outputfile, "\n\\ %s\n",
Packit 33f14e
			 _("No newline at end of file"));
Packit 33f14e
	    }
Packit 33f14e
	}
Packit 33f14e
    }
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
Packit 33f14e
/* Output to OUTPUTFILE the lines of B taken from FILENUM.  Double any
Packit 33f14e
   initial '.'s; yield nonzero if any initial '.'s were doubled.  */
Packit 33f14e
Packit 33f14e
static bool
Packit 33f14e
dotlines (FILE *outputfile, struct diff3_block *b, int filenum)
Packit 33f14e
{
Packit 33f14e
  lin i;
Packit 33f14e
  bool leading_dot = false;
Packit 33f14e
Packit 33f14e
  for (i = 0;
Packit 33f14e
       i < D_NUMLINES (b, filenum);
Packit 33f14e
       i++)
Packit 33f14e
    {
Packit 33f14e
      char *line = D_RELNUM (b, filenum, i);
Packit 33f14e
      if (line[0] == '.')
Packit 33f14e
	{
Packit 33f14e
	  leading_dot = true;
Packit 33f14e
	  fputc ('.', outputfile);
Packit 33f14e
	}
Packit 33f14e
      fwrite (line, sizeof (char),
Packit 33f14e
	      D_RELLEN (b, filenum, i), outputfile);
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return leading_dot;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Output to OUTPUTFILE a '.' line.  If LEADING_DOT is true, also
Packit 33f14e
   output a command that removes initial '.'s starting with line START
Packit 33f14e
   and continuing for NUM lines.  */
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
undotlines (FILE *outputfile, bool leading_dot, printint start, printint num)
Packit 33f14e
{
Packit 33f14e
  fputs (".\n", outputfile);
Packit 33f14e
  if (leading_dot)
Packit 33f14e
    {
Packit 33f14e
      if (num == 1)
Packit 33f14e
	fprintf (outputfile, "%"pI"ds/^\\.//\n", start);
Packit 33f14e
      else
Packit 33f14e
	fprintf (outputfile, "%"pI"d,%"pI"ds/^\\.//\n", start, start + num - 1);
Packit 33f14e
    }
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Output a diff3 set of blocks as an ed script.  This script applies
Packit 33f14e
   the changes between file's 2 & 3 to file 1.  Take the precise
Packit 33f14e
   format of the ed script to be output from global variables set
Packit 33f14e
   during options processing.  Reverse the order of
Packit 33f14e
   the set of diff3 blocks in DIFF; this gets
Packit 33f14e
   around the problems involved with changing line numbers in an ed
Packit 33f14e
   script.
Packit 33f14e
Packit 33f14e
   As in 'output_diff3', the variable MAPPING maps from file number
Packit 33f14e
   according to the argument list to file number according to the diff
Packit 33f14e
   passed.  All files listed below are in terms of the argument list.
Packit 33f14e
   REV_MAPPING is the inverse of MAPPING.
Packit 33f14e
Packit 33f14e
   FILE0, FILE1 and FILE2 are the strings to print as the names of the
Packit 33f14e
   three files.  These may be the actual names, or may be the
Packit 33f14e
   arguments specified with -L.
Packit 33f14e
Packit 33f14e
   Return 1 if conflicts were found.  */
Packit 33f14e
Packit 33f14e
static bool
Packit 33f14e
output_diff3_edscript (FILE *outputfile, struct diff3_block *diff,
Packit 33f14e
		       int const mapping[3], int const rev_mapping[3],
Packit 33f14e
		       char const *file0, char const *file1, char const *file2)
Packit 33f14e
{
Packit 33f14e
  bool leading_dot;
Packit 33f14e
  bool conflicts_found = false;
Packit 33f14e
  bool conflict;
Packit 33f14e
  struct diff3_block *b;
Packit 33f14e
Packit 33f14e
  for (b = reverse_diff3_blocklist (diff); b; b = b->next)
Packit 33f14e
    {
Packit 33f14e
      /* Must do mapping correctly.  */
Packit 33f14e
      enum diff_type type
Packit 33f14e
	= (b->correspond == DIFF_ALL
Packit 33f14e
	   ? DIFF_ALL
Packit 33f14e
	   : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
Packit 33f14e
Packit 33f14e
      printint low0, high0;
Packit 33f14e
Packit 33f14e
      /* If we aren't supposed to do this output block, skip it.  */
Packit 33f14e
      switch (type)
Packit 33f14e
	{
Packit 33f14e
	default: continue;
Packit 33f14e
	case DIFF_2ND: if (!show_2nd) continue; conflict = true; break;
Packit 33f14e
	case DIFF_3RD: if (overlap_only) continue; conflict = false; break;
Packit 33f14e
	case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      low0 = D_LOWLINE (b, mapping[FILE0]);
Packit 33f14e
      high0 = D_HIGHLINE (b, mapping[FILE0]);
Packit 33f14e
Packit 33f14e
      if (conflict)
Packit 33f14e
	{
Packit 33f14e
	  conflicts_found = true;
Packit 33f14e
Packit 33f14e
Packit 33f14e
	  /* Mark end of conflict.  */
Packit 33f14e
Packit 33f14e
	  fprintf (outputfile, "%"pI"da\n", high0);
Packit 33f14e
	  leading_dot = false;
Packit 33f14e
	  if (type == DIFF_ALL)
Packit 33f14e
	    {
Packit 33f14e
	      if (show_2nd)
Packit 33f14e
		{
Packit 33f14e
		  /* Append lines from FILE1.  */
Packit 33f14e
		  fprintf (outputfile, "||||||| %s\n", file1);
Packit 33f14e
		  leading_dot = dotlines (outputfile, b, mapping[FILE1]);
Packit 33f14e
		}
Packit 33f14e
	      /* Append lines from FILE2.  */
Packit 33f14e
	      fputs ("=======\n", outputfile);
Packit 33f14e
	      leading_dot |= dotlines (outputfile, b, mapping[FILE2]);
Packit 33f14e
	    }
Packit 33f14e
	  fprintf (outputfile, ">>>>>>> %s\n", file2);
Packit 33f14e
	  undotlines (outputfile, leading_dot, high0 + 2,
Packit 33f14e
		      (D_NUMLINES (b, mapping[FILE1])
Packit 33f14e
		       + D_NUMLINES (b, mapping[FILE2]) + 1));
Packit 33f14e
Packit 33f14e
Packit 33f14e
	  /* Mark start of conflict.  */
Packit 33f14e
Packit 33f14e
	  fprintf (outputfile, "%"pI"da\n<<<<<<< %s\n", low0 - 1,
Packit 33f14e
		   type == DIFF_ALL ? file0 : file1);
Packit 33f14e
	  leading_dot = false;
Packit 33f14e
	  if (type == DIFF_2ND)
Packit 33f14e
	    {
Packit 33f14e
	      /* Prepend lines from FILE1.  */
Packit 33f14e
	      leading_dot = dotlines (outputfile, b, mapping[FILE1]);
Packit 33f14e
	      fputs ("=======\n", outputfile);
Packit 33f14e
	    }
Packit 33f14e
	  undotlines (outputfile, leading_dot, low0 + 1,
Packit 33f14e
		      D_NUMLINES (b, mapping[FILE1]));
Packit 33f14e
	}
Packit 33f14e
      else if (D_NUMLINES (b, mapping[FILE2]) == 0)
Packit 33f14e
	/* Write out a delete */
Packit 33f14e
	{
Packit 33f14e
	  if (low0 == high0)
Packit 33f14e
	    fprintf (outputfile, "%"pI"dd\n", low0);
Packit 33f14e
	  else
Packit 33f14e
	    fprintf (outputfile, "%"pI"d,%"pI"dd\n", low0, high0);
Packit 33f14e
	}
Packit 33f14e
      else
Packit 33f14e
	/* Write out an add or change */
Packit 33f14e
	{
Packit 33f14e
	  switch (high0 - low0)
Packit 33f14e
	    {
Packit 33f14e
	    case -1:
Packit 33f14e
	      fprintf (outputfile, "%"pI"da\n", high0);
Packit 33f14e
	      break;
Packit 33f14e
	    case 0:
Packit 33f14e
	      fprintf (outputfile, "%"pI"dc\n", high0);
Packit 33f14e
	      break;
Packit 33f14e
	    default:
Packit 33f14e
	      fprintf (outputfile, "%"pI"d,%"pI"dc\n", low0, high0);
Packit 33f14e
	      break;
Packit 33f14e
	    }
Packit 33f14e
Packit 33f14e
	  undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]),
Packit 33f14e
		      low0, D_NUMLINES (b, mapping[FILE2]));
Packit 33f14e
	}
Packit 33f14e
    }
Packit 33f14e
  if (finalwrite)
Packit 33f14e
    fputs ("w\nq\n", outputfile);
Packit 33f14e
  return conflicts_found;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Read from INFILE and output to OUTPUTFILE a set of diff3_blocks
Packit 33f14e
   DIFF as a merged file.  This acts like 'ed file0
Packit 33f14e
   <[output_diff3_edscript]', except that it works even for binary
Packit 33f14e
   data or incomplete lines.
Packit 33f14e
Packit 33f14e
   As before, MAPPING maps from arg list file number to diff file
Packit 33f14e
   number, REV_MAPPING is its inverse, and FILE0, FILE1, and FILE2 are
Packit 33f14e
   the names of the files.
Packit 33f14e
Packit 33f14e
   Return 1 if conflicts were found.  */
Packit 33f14e
Packit 33f14e
static bool
Packit 33f14e
output_diff3_merge (FILE *infile, FILE *outputfile, struct diff3_block *diff,
Packit 33f14e
		    int const mapping[3], int const rev_mapping[3],
Packit 33f14e
		    char const *file0, char const *file1, char const *file2)
Packit 33f14e
{
Packit 33f14e
  int c;
Packit 33f14e
  lin i;
Packit 33f14e
  bool conflicts_found = false;
Packit 33f14e
  bool conflict;
Packit 33f14e
  struct diff3_block *b;
Packit 33f14e
  lin linesread = 0;
Packit 33f14e
Packit 33f14e
  for (b = diff; b; b = b->next)
Packit 33f14e
    {
Packit 33f14e
      /* Must do mapping correctly.  */
Packit 33f14e
      enum diff_type type
Packit 33f14e
	= ((b->correspond == DIFF_ALL)
Packit 33f14e
	   ? DIFF_ALL
Packit 33f14e
	   : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
Packit 33f14e
      char const *format_2nd = "<<<<<<< %s\n";
Packit 33f14e
Packit 33f14e
      /* If we aren't supposed to do this output block, skip it.  */
Packit 33f14e
      switch (type)
Packit 33f14e
	{
Packit 33f14e
	default: continue;
Packit 33f14e
	case DIFF_2ND: if (!show_2nd) continue; conflict = true; break;
Packit 33f14e
	case DIFF_3RD: if (overlap_only) continue; conflict = false; break;
Packit 33f14e
	case DIFF_ALL: if (simple_only) continue; conflict = flagging;
Packit 33f14e
	  format_2nd = "||||||| %s\n";
Packit 33f14e
	  break;
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      /* Copy I lines from file 0.  */
Packit 33f14e
      i = D_LOWLINE (b, FILE0) - linesread - 1;
Packit 33f14e
      linesread += i;
Packit 33f14e
      while (0 <= --i)
Packit 33f14e
	do
Packit 33f14e
	  {
Packit 33f14e
	    c = getc (infile);
Packit 33f14e
	    if (c == EOF)
Packit 33f14e
	      {
Packit 33f14e
		if (ferror (infile))
Packit 33f14e
		  perror_with_exit (_("read failed"));
Packit 33f14e
		else if (feof (infile))
Packit 33f14e
		  fatal ("input file shrank");
Packit 33f14e
	      }
Packit 33f14e
	    putc (c, outputfile);
Packit 33f14e
	  }
Packit 33f14e
	while (c != '\n');
Packit 33f14e
Packit 33f14e
      if (conflict)
Packit 33f14e
	{
Packit 33f14e
	  conflicts_found = true;
Packit 33f14e
Packit 33f14e
	  if (type == DIFF_ALL)
Packit 33f14e
	    {
Packit 33f14e
	      /* Put in lines from FILE0 with bracket.  */
Packit 33f14e
	      fprintf (outputfile, "<<<<<<< %s\n", file0);
Packit 33f14e
	      for (i = 0;
Packit 33f14e
		   i < D_NUMLINES (b, mapping[FILE0]);
Packit 33f14e
		   i++)
Packit 33f14e
		fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
Packit 33f14e
			D_RELLEN (b, mapping[FILE0], i), outputfile);
Packit 33f14e
	    }
Packit 33f14e
Packit 33f14e
	  if (show_2nd)
Packit 33f14e
	    {
Packit 33f14e
	      /* Put in lines from FILE1 with bracket.  */
Packit 33f14e
	      fprintf (outputfile, format_2nd, file1);
Packit 33f14e
	      for (i = 0;
Packit 33f14e
		   i < D_NUMLINES (b, mapping[FILE1]);
Packit 33f14e
		   i++)
Packit 33f14e
		fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char),
Packit 33f14e
			D_RELLEN (b, mapping[FILE1], i), outputfile);
Packit 33f14e
	    }
Packit 33f14e
Packit 33f14e
	  fputs ("=======\n", outputfile);
Packit 33f14e
	}
Packit 33f14e
Packit 33f14e
      /* Put in lines from FILE2.  */
Packit 33f14e
      for (i = 0;
Packit 33f14e
	   i < D_NUMLINES (b, mapping[FILE2]);
Packit 33f14e
	   i++)
Packit 33f14e
	fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
Packit 33f14e
		D_RELLEN (b, mapping[FILE2], i), outputfile);
Packit 33f14e
Packit 33f14e
      if (conflict)
Packit 33f14e
	fprintf (outputfile, ">>>>>>> %s\n", file2);
Packit 33f14e
Packit 33f14e
      /* Skip I lines in file 0.  */
Packit 33f14e
      i = D_NUMLINES (b, FILE0);
Packit 33f14e
      linesread += i;
Packit 33f14e
      while (0 <= --i)
Packit 33f14e
	while ((c = getc (infile)) != '\n')
Packit 33f14e
	  if (c == EOF)
Packit 33f14e
	    {
Packit 33f14e
	      if (ferror (infile))
Packit 33f14e
		perror_with_exit (_("read failed"));
Packit 33f14e
	      else if (feof (infile))
Packit 33f14e
		{
Packit 33f14e
		  if (i || b->next)
Packit 33f14e
		    fatal ("input file shrank");
Packit 33f14e
		  return conflicts_found;
Packit 33f14e
		}
Packit 33f14e
	    }
Packit 33f14e
    }
Packit 33f14e
  /* Copy rest of common file.  */
Packit 33f14e
  while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
Packit 33f14e
    putc (c, outputfile);
Packit 33f14e
  return conflicts_found;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Reverse the order of the list of diff3 blocks.  */
Packit 33f14e
Packit 33f14e
static struct diff3_block *
Packit 33f14e
reverse_diff3_blocklist (struct diff3_block *diff)
Packit 33f14e
{
Packit 33f14e
  register struct diff3_block *tmp, *next, *prev;
Packit 33f14e
Packit 33f14e
  for (tmp = diff, prev = 0;  tmp;  tmp = next)
Packit 33f14e
    {
Packit 33f14e
      next = tmp->next;
Packit 33f14e
      tmp->next = prev;
Packit 33f14e
      prev = tmp;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return prev;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
fatal (char const *msgid)
Packit 33f14e
{
Packit 33f14e
  die (EXIT_TROUBLE, 0, "%s", _(msgid));
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
perror_with_exit (char const *string)
Packit 33f14e
{
Packit 33f14e
  die (EXIT_TROUBLE, errno, "%s", string);
Packit 33f14e
}