xref: /freebsd/contrib/diff/src/diff3.c (revision 15752fa8582f3f77b0504f977b08378b93c4c8a7)
1  /* diff3 - compare three files line by line
2  
3     Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1998, 2001,
4     2002, 2004 Free Software Foundation, Inc.
5  
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2, or (at your option)
9     any later version.
10  
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14     See the GNU General Public License for more details.
15  
16     You should have received a copy of the GNU General Public License
17     along with this program; see the file COPYING.
18     If not, write to the Free Software Foundation,
19     59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20  
21  #include "system.h"
22  #include "paths.h"
23  
24  #include <stdio.h>
25  #include <unlocked-io.h>
26  
27  #include <c-stack.h>
28  #include <cmpbuf.h>
29  #include <error.h>
30  #include <exitfail.h>
31  #include <file-type.h>
32  #include <getopt.h>
33  #include <inttostr.h>
34  #include <quotesys.h>
35  #include <version-etc.h>
36  #include <xalloc.h>
37  
38  /* Internal data structures and macros for the diff3 program; includes
39     data structures for both diff3 diffs and normal diffs.  */
40  
41  /* Different files within a three way diff.  */
42  #define	FILE0	0
43  #define	FILE1	1
44  #define	FILE2	2
45  
46  /* A three way diff is built from two two-way diffs; the file which
47     the two two-way diffs share is:  */
48  #define	FILEC	FILE2
49  
50  /* Different files within a two way diff.
51     FC is the common file, FO the other file.  */
52  #define FO 0
53  #define FC 1
54  
55  /* The ranges are indexed by */
56  #define	RANGE_START	0
57  #define	RANGE_END	1
58  
59  enum diff_type {
60    ERROR,			/* Should not be used */
61    ADD,				/* Two way diff add */
62    CHANGE,			/* Two way diff change */
63    DELETE,			/* Two way diff delete */
64    DIFF_ALL,			/* All three are different */
65    DIFF_1ST,			/* Only the first is different */
66    DIFF_2ND,			/* Only the second */
67    DIFF_3RD			/* Only the third */
68  };
69  
70  /* Two way diff */
71  struct diff_block {
72    lin ranges[2][2];		/* Ranges are inclusive */
73    char **lines[2];		/* The actual lines (may contain nulls) */
74    size_t *lengths[2];		/* Line lengths (including newlines, if any) */
75    struct diff_block *next;
76  };
77  
78  /* Three way diff */
79  
80  struct diff3_block {
81    enum diff_type correspond;	/* Type of diff */
82    lin ranges[3][2];		/* Ranges are inclusive */
83    char **lines[3];		/* The actual lines (may contain nulls) */
84    size_t *lengths[3];		/* Line lengths (including newlines, if any) */
85    struct diff3_block *next;
86  };
87  
88  /* Access the ranges on a diff block.  */
89  #define	D_LOWLINE(diff, filenum)	\
90    ((diff)->ranges[filenum][RANGE_START])
91  #define	D_HIGHLINE(diff, filenum)	\
92    ((diff)->ranges[filenum][RANGE_END])
93  #define	D_NUMLINES(diff, filenum)	\
94    (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
95  
96  /* Access the line numbers in a file in a diff by relative line
97     numbers (i.e. line number within the diff itself).  Note that these
98     are lvalues and can be used for assignment.  */
99  #define	D_RELNUM(diff, filenum, linenum)	\
100    ((diff)->lines[filenum][linenum])
101  #define	D_RELLEN(diff, filenum, linenum)	\
102    ((diff)->lengths[filenum][linenum])
103  
104  /* And get at them directly, when that should be necessary.  */
105  #define	D_LINEARRAY(diff, filenum)	\
106    ((diff)->lines[filenum])
107  #define	D_LENARRAY(diff, filenum)	\
108    ((diff)->lengths[filenum])
109  
110  /* Next block.  */
111  #define	D_NEXT(diff)	((diff)->next)
112  
113  /* Access the type of a diff3 block.  */
114  #define	D3_TYPE(diff)	((diff)->correspond)
115  
116  /* Line mappings based on diffs.  The first maps off the top of the
117     diff, the second off of the bottom.  */
118  #define	D_HIGH_MAPLINE(diff, fromfile, tofile, linenum)	\
119    ((linenum)						\
120     - D_HIGHLINE ((diff), (fromfile))			\
121     + D_HIGHLINE ((diff), (tofile)))
122  
123  #define	D_LOW_MAPLINE(diff, fromfile, tofile, linenum)	\
124    ((linenum)						\
125     - D_LOWLINE ((diff), (fromfile))			\
126     + D_LOWLINE ((diff), (tofile)))
127  
128  /* Options variables for flags set on command line.  */
129  
130  /* If nonzero, treat all files as text files, never as binary.  */
131  static bool text;
132  
133  /* Remove trailing carriage returns from input.  */
134  static bool strip_trailing_cr;
135  
136  /* If nonzero, write out an ed script instead of the standard diff3 format.  */
137  static bool edscript;
138  
139  /* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
140     preserve the lines which would normally be deleted from
141     file 1 with a special flagging mechanism.  */
142  static bool flagging;
143  
144  /* Use a tab to align output lines (-T).  */
145  static bool initial_tab;
146  
147  /* If nonzero, do not output information for overlapping diffs.  */
148  static bool simple_only;
149  
150  /* If nonzero, do not output information for non-overlapping diffs.  */
151  static bool overlap_only;
152  
153  /* If nonzero, show information for DIFF_2ND diffs.  */
154  static bool show_2nd;
155  
156  /* If nonzero, include `:wq' at the end of the script
157     to write out the file being edited.   */
158  static bool finalwrite;
159  
160  /* If nonzero, output a merged file.  */
161  static bool merge;
162  
163  char *program_name;
164  
165  static char *read_diff (char const *, char const *, char **);
166  static char *scan_diff_line (char *, char **, size_t *, char *, char);
167  static enum diff_type process_diff_control (char **, struct diff_block *);
168  static bool compare_line_list (char * const[], size_t const[], char * const[], size_t const[], lin);
169  static bool copy_stringlist (char * const[], size_t const[], char *[], size_t[], lin);
170  static bool output_diff3_edscript (FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
171  static bool output_diff3_merge (FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
172  static struct diff3_block *create_diff3_block (lin, lin, lin, lin, lin, lin);
173  static struct diff3_block *make_3way_diff (struct diff_block *, struct diff_block *);
174  static struct diff3_block *reverse_diff3_blocklist (struct diff3_block *);
175  static struct diff3_block *using_to_diff3_block (struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *);
176  static struct diff_block *process_diff (char const *, char const *, struct diff_block **);
177  static void check_stdout (void);
178  static void fatal (char const *) __attribute__((noreturn));
179  static void output_diff3 (FILE *, struct diff3_block *, int const[3], int const[3]);
180  static void perror_with_exit (char const *) __attribute__((noreturn));
181  static void try_help (char const *, char const *) __attribute__((noreturn));
182  static void usage (void);
183  
184  static char const *diff_program = DEFAULT_DIFF_PROGRAM;
185  
186  /* Values for long options that do not have single-letter equivalents.  */
187  enum
188  {
189    DIFF_PROGRAM_OPTION = CHAR_MAX + 1,
190    HELP_OPTION,
191    STRIP_TRAILING_CR_OPTION
192  };
193  
194  static struct option const longopts[] =
195  {
196    {"diff-program", 1, 0, DIFF_PROGRAM_OPTION},
197    {"easy-only", 0, 0, '3'},
198    {"ed", 0, 0, 'e'},
199    {"help", 0, 0, HELP_OPTION},
200    {"initial-tab", 0, 0, 'T'},
201    {"label", 1, 0, 'L'},
202    {"merge", 0, 0, 'm'},
203    {"overlap-only", 0, 0, 'x'},
204    {"show-all", 0, 0, 'A'},
205    {"show-overlap", 0, 0, 'E'},
206    {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},
207    {"text", 0, 0, 'a'},
208    {"version", 0, 0, 'v'},
209    {0, 0, 0, 0}
210  };
211  
212  int
213  main (int argc, char **argv)
214  {
215    int c, i;
216    int common;
217    int mapping[3];
218    int rev_mapping[3];
219    int incompat = 0;
220    bool conflicts_found;
221    struct diff_block *thread0, *thread1, *last_block;
222    struct diff3_block *diff3;
223    int tag_count = 0;
224    char *tag_strings[3];
225    char *commonname;
226    char **file;
227    struct stat statb;
228  
229    exit_failure = 2;
230    initialize_main (&argc, &argv);
231    program_name = argv[0];
232    setlocale (LC_ALL, "");
233    bindtextdomain (PACKAGE, LOCALEDIR);
234    textdomain (PACKAGE);
235    c_stack_action (0);
236  
237    while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != -1)
238      {
239        switch (c)
240  	{
241  	case 'a':
242  	  text = true;
243  	  break;
244  	case 'A':
245  	  show_2nd = true;
246  	  flagging = true;
247  	  incompat++;
248  	  break;
249  	case 'x':
250  	  overlap_only = true;
251  	  incompat++;
252  	  break;
253  	case '3':
254  	  simple_only = true;
255  	  incompat++;
256  	  break;
257  	case 'i':
258  	  finalwrite = true;
259  	  break;
260  	case 'm':
261  	  merge = true;
262  	  break;
263  	case 'X':
264  	  overlap_only = true;
265  	  /* Fall through.  */
266  	case 'E':
267  	  flagging = true;
268  	  /* Fall through.  */
269  	case 'e':
270  	  incompat++;
271  	  break;
272  	case 'T':
273  	  initial_tab = true;
274  	  break;
275  	case STRIP_TRAILING_CR_OPTION:
276  	  strip_trailing_cr = true;
277  	  break;
278  	case 'v':
279  	  version_etc (stdout, "diff3", PACKAGE_NAME, PACKAGE_VERSION,
280  		       "Randy Smith", (char *) 0);
281  	  check_stdout ();
282  	  return EXIT_SUCCESS;
283  	case DIFF_PROGRAM_OPTION:
284  	  diff_program = optarg;
285  	  break;
286  	case HELP_OPTION:
287  	  usage ();
288  	  check_stdout ();
289  	  return EXIT_SUCCESS;
290  	case 'L':
291  	  /* Handle up to three -L options.  */
292  	  if (tag_count < 3)
293  	    {
294  	      tag_strings[tag_count++] = optarg;
295  	      break;
296  	    }
297  	  try_help ("too many file label options", 0);
298  	default:
299  	  try_help (0, 0);
300  	}
301      }
302  
303    edscript = incompat & ~merge;  /* -AeExX3 without -m implies ed script.  */
304    show_2nd |= ~incompat & merge;  /* -m without -AeExX3 implies -A.  */
305    flagging |= ~incompat & merge;
306  
307    if (incompat > 1  /* Ensure at most one of -AeExX3.  */
308        || finalwrite & merge /* -i -m would rewrite input file.  */
309        || (tag_count && ! flagging)) /* -L requires one of -AEX.  */
310      try_help ("incompatible options", 0);
311  
312    if (argc - optind != 3)
313      {
314        if (argc - optind < 3)
315  	try_help ("missing operand after `%s'", argv[argc - 1]);
316        else
317  	try_help ("extra operand `%s'", argv[optind + 3]);
318      }
319  
320    file = &argv[optind];
321  
322    for (i = tag_count; i < 3; i++)
323      tag_strings[i] = file[i];
324  
325    /* Always compare file1 to file2, even if file2 is "-".
326       This is needed for -mAeExX3.  Using the file0 as
327       the common file would produce wrong results, because if the
328       file0-file1 diffs didn't line up with the file0-file2 diffs
329       (which is entirely possible since we don't use diff's -n option),
330       diff3 might report phantom changes from file1 to file2.
331  
332       Also, try to compare file0 to file1, because this is where
333       changes are expected to come from.  Diffing between these pairs
334       of files is more likely to avoid phantom changes from file0 to file1.
335  
336       Historically, the default common file was file2, so some older
337       applications (e.g. Emacs ediff) used file2 as the ancestor.  So,
338       for compatibility, if this is a 3-way diff (not a merge or
339       edscript), prefer file2 as the common file.  */
340  
341    common = 2 - (edscript | merge);
342  
343    if (strcmp (file[common], "-") == 0)
344      {
345        /* Sigh.  We've got standard input as the common file.  We can't
346  	 call diff twice on stdin.  Use the other arg as the common
347  	 file instead.  */
348        common = 3 - common;
349        if (strcmp (file[0], "-") == 0 || strcmp (file[common], "-") == 0)
350  	fatal ("`-' specified for more than one input file");
351      }
352  
353    mapping[0] = 0;
354    mapping[1] = 3 - common;
355    mapping[2] = common;
356  
357    for (i = 0; i < 3; i++)
358      rev_mapping[mapping[i]] = i;
359  
360    for (i = 0; i < 3; i++)
361      if (strcmp (file[i], "-") != 0)
362        {
363  	if (stat (file[i], &statb) < 0)
364  	  perror_with_exit (file[i]);
365  	else if (S_ISDIR (statb.st_mode))
366  	  error (EXIT_TROUBLE, EISDIR, "%s", file[i]);
367        }
368  
369  #ifdef SIGCHLD
370    /* System V fork+wait does not work if SIGCHLD is ignored.  */
371    signal (SIGCHLD, SIG_DFL);
372  #endif
373  
374    /* Invoke diff twice on two pairs of input files, combine the two
375       diffs, and output them.  */
376  
377    commonname = file[rev_mapping[FILEC]];
378    thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
379    thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block);
380    diff3 = make_3way_diff (thread0, thread1);
381    if (edscript)
382      conflicts_found
383        = output_diff3_edscript (stdout, diff3, mapping, rev_mapping,
384  			       tag_strings[0], tag_strings[1], tag_strings[2]);
385    else if (merge)
386      {
387        if (! freopen (file[rev_mapping[FILE0]], "r", stdin))
388  	perror_with_exit (file[rev_mapping[FILE0]]);
389        conflicts_found
390  	= output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping,
391  			      tag_strings[0], tag_strings[1], tag_strings[2]);
392        if (ferror (stdin))
393  	fatal ("read failed");
394      }
395    else
396      {
397        output_diff3 (stdout, diff3, mapping, rev_mapping);
398        conflicts_found = false;
399      }
400  
401    check_stdout ();
402    exit (conflicts_found);
403    return conflicts_found;
404  }
405  
406  static void
407  try_help (char const *reason_msgid, char const *operand)
408  {
409    if (reason_msgid)
410      error (0, 0, _(reason_msgid), operand);
411    error (EXIT_TROUBLE, 0,
412  	 _("Try `%s --help' for more information."), program_name);
413    abort ();
414  }
415  
416  static void
417  check_stdout (void)
418  {
419    if (ferror (stdout))
420      fatal ("write failed");
421    else if (fclose (stdout) != 0)
422      perror_with_exit (_("standard output"));
423  }
424  
425  static char const * const option_help_msgid[] = {
426    N_("-e  --ed  Output unmerged changes from OLDFILE to YOURFILE into MYFILE."),
427    N_("-E  --show-overlap  Output unmerged changes, bracketing conflicts."),
428    N_("-A  --show-all  Output all changes, bracketing conflicts."),
429    N_("-x  --overlap-only  Output overlapping changes."),
430    N_("-X  Output overlapping changes, bracketing them."),
431    N_("-3  --easy-only  Output unmerged nonoverlapping changes."),
432    "",
433    N_("-m  --merge  Output merged file instead of ed script (default -A)."),
434    N_("-L LABEL  --label=LABEL  Use LABEL instead of file name."),
435    N_("-i  Append `w' and `q' commands to ed scripts."),
436    N_("-a  --text  Treat all files as text."),
437    N_("--strip-trailing-cr  Strip trailing carriage return on input."),
438    N_("-T  --initial-tab  Make tabs line up by prepending a tab."),
439    N_("--diff-program=PROGRAM  Use PROGRAM to compare files."),
440    "",
441    N_("-v  --version  Output version info."),
442    N_("--help  Output this help."),
443    0
444  };
445  
446  static void
447  usage (void)
448  {
449    char const * const *p;
450  
451    printf (_("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n"),
452  	  program_name);
453    printf ("%s\n\n", _("Compare three files line by line."));
454    for (p = option_help_msgid;  *p;  p++)
455      if (**p)
456        printf ("  %s\n", _(*p));
457      else
458        putchar ('\n');
459    printf ("\n%s\n%s\n\n%s\n",
460  	  _("If a FILE is `-', read standard input."),
461  	  _("Exit status is 0 if successful, 1 if conflicts, 2 if trouble."),
462  	  _("Report bugs to <bug-gnu-utils@gnu.org>."));
463  }
464  
465  /* Combine the two diffs together into one.
466     Here is the algorithm:
467  
468       File2 is shared in common between the two diffs.
469       Diff02 is the diff between 0 and 2.
470       Diff12 is the diff between 1 and 2.
471  
472  	1) Find the range for the first block in File2.
473  	    a) Take the lowest of the two ranges (in File2) in the two
474  	       current blocks (one from each diff) as being the low
475  	       water mark.  Assign the upper end of this block as
476  	       being the high water mark and move the current block up
477  	       one.  Mark the block just moved over as to be used.
478  	    b) Check the next block in the diff that the high water
479  	       mark is *not* from.
480  
481  	       *If* the high water mark is above
482  	       the low end of the range in that block,
483  
484  		   mark that block as to be used and move the current
485  		   block up.  Set the high water mark to the max of
486  		   the high end of this block and the current.  Repeat b.
487  
488  	 2) Find the corresponding ranges in File0 (from the blocks
489  	    in diff02; line per line outside of diffs) and in File1.
490  	    Create a diff3_block, reserving space as indicated by the ranges.
491  
492  	 3) Copy all of the pointers for file2 in.  At least for now,
493  	    do memcmp's between corresponding strings in the two diffs.
494  
495  	 4) Copy all of the pointers for file0 and 1 in.  Get what is
496  	    needed from file2 (when there isn't a diff block, it's
497  	    identical to file2 within the range between diff blocks).
498  
499  	 5) If the diff blocks used came from only one of the two
500  	    strings of diffs, then that file (i.e. the one other than
501  	    the common file in that diff) is the odd person out.  If
502  	    diff blocks are used from both sets, check to see if files
503  	    0 and 1 match:
504  
505  		Same number of lines?  If so, do a set of memcmp's (if
506  	    a memcmp matches; copy the pointer over; it'll be easier
507  	    later during comparisons).  If they match, 0 & 1 are the
508  	    same.  If not, all three different.
509  
510       Then do it again, until the blocks are exhausted.  */
511  
512  
513  /* Make a three way diff (chain of diff3_block's) from two two way
514     diffs (chains of diff_block's).  Assume that each of the two diffs
515     passed are onto the same file (i.e. that each of the diffs were
516     made "to" the same file).  Return a three way diff pointer with
517     numbering FILE0 = the other file in diff02, FILE1 = the other file
518     in diff12, and FILEC = the common file.  */
519  
520  static struct diff3_block *
521  make_3way_diff (struct diff_block *thread0, struct diff_block *thread1)
522  {
523    /* Work on the two diffs passed to it as threads.  Thread number 0
524       is diff02, thread number 1 is diff12.  USING is the base of the
525       list of blocks to be used to construct each block of the three
526       way diff; if no blocks from a particular thread are to be used,
527       that element of USING is 0.  LAST_USING contains the last
528       elements on each of the using lists.
529  
530       HIGH_WATER_MARK is the highest line number in the common file
531       described in any of the diffs in either of the USING lists.
532       HIGH_WATER_THREAD names the thread.  Similarly BASE_WATER_MARK
533       and BASE_WATER_THREAD describe the lowest line number in the
534       common file described in any of the diffs in either of the USING
535       lists.  HIGH_WATER_DIFF is the diff from which the
536       HIGH_WATER_MARK was taken.
537  
538       HIGH_WATER_DIFF should always be equal to
539       LAST_USING[HIGH_WATER_THREAD].  OTHER_DIFF is the next diff to
540       check for higher water, and should always be equal to
541       CURRENT[HIGH_WATER_THREAD ^ 1].  OTHER_THREAD is the thread in
542       which the OTHER_DIFF is, and hence should always be equal to
543       HIGH_WATER_THREAD ^ 1.
544  
545       LAST_DIFF is the last diff block produced by this routine, for
546       line correspondence purposes between that diff and the one
547       currently being worked on.  It is ZERO_DIFF before any blocks
548       have been created.  */
549  
550    struct diff_block *using[2];
551    struct diff_block *last_using[2];
552    struct diff_block *current[2];
553  
554    lin high_water_mark;
555  
556    int high_water_thread;
557    int base_water_thread;
558    int other_thread;
559  
560    struct diff_block *high_water_diff;
561    struct diff_block *other_diff;
562  
563    struct diff3_block *result;
564    struct diff3_block *tmpblock;
565    struct diff3_block **result_end;
566  
567    struct diff3_block const *last_diff3;
568  
569    static struct diff3_block const zero_diff3;
570  
571    /* Initialization */
572    result = 0;
573    result_end = &result;
574    current[0] = thread0; current[1] = thread1;
575    last_diff3 = &zero_diff3;
576  
577    /* Sniff up the threads until we reach the end */
578  
579    while (current[0] || current[1])
580      {
581        using[0] = using[1] = last_using[0] = last_using[1] = 0;
582  
583        /* Setup low and high water threads, diffs, and marks.  */
584        if (!current[0])
585  	base_water_thread = 1;
586        else if (!current[1])
587  	base_water_thread = 0;
588        else
589  	base_water_thread =
590  	  (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
591  
592        high_water_thread = base_water_thread;
593  
594        high_water_diff = current[high_water_thread];
595  
596        high_water_mark = D_HIGHLINE (high_water_diff, FC);
597  
598        /* Make the diff you just got info from into the using class */
599        using[high_water_thread]
600  	= last_using[high_water_thread]
601  	= high_water_diff;
602        current[high_water_thread] = high_water_diff->next;
603        last_using[high_water_thread]->next = 0;
604  
605        /* And mark the other diff */
606        other_thread = high_water_thread ^ 0x1;
607        other_diff = current[other_thread];
608  
609        /* Shuffle up the ladder, checking the other diff to see if it
610  	 needs to be incorporated.  */
611        while (other_diff
612  	     && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
613  	{
614  
615  	  /* Incorporate this diff into the using list.  Note that
616  	     this doesn't take it off the current list */
617  	  if (using[other_thread])
618  	    last_using[other_thread]->next = other_diff;
619  	  else
620  	    using[other_thread] = other_diff;
621  	  last_using[other_thread] = other_diff;
622  
623  	  /* Take it off the current list.  Note that this following
624  	     code assumes that other_diff enters it equal to
625  	     current[high_water_thread ^ 0x1] */
626  	  current[other_thread] = current[other_thread]->next;
627  	  other_diff->next = 0;
628  
629  	  /* Set the high_water stuff
630  	     If this comparison is equal, then this is the last pass
631  	     through this loop; since diff blocks within a given
632  	     thread cannot overlap, the high_water_mark will be
633  	     *below* the range_start of either of the next diffs.  */
634  
635  	  if (high_water_mark < D_HIGHLINE (other_diff, FC))
636  	    {
637  	      high_water_thread ^= 1;
638  	      high_water_diff = other_diff;
639  	      high_water_mark = D_HIGHLINE (other_diff, FC);
640  	    }
641  
642  	  /* Set the other diff */
643  	  other_thread = high_water_thread ^ 0x1;
644  	  other_diff = current[other_thread];
645  	}
646  
647        /* The using lists contain a list of all of the blocks to be
648  	 included in this diff3_block.  Create it.  */
649  
650        tmpblock = using_to_diff3_block (using, last_using,
651  				       base_water_thread, high_water_thread,
652  				       last_diff3);
653  
654        if (!tmpblock)
655  	fatal ("internal error: screwup in format of diff blocks");
656  
657        /* Put it on the list.  */
658        *result_end = tmpblock;
659        result_end = &tmpblock->next;
660  
661        /* Set up corresponding lines correctly.  */
662        last_diff3 = tmpblock;
663      }
664    return result;
665  }
666  
667  /* Take two lists of blocks (from two separate diff threads) and put
668     them together into one diff3 block.  Return a pointer to this diff3
669     block or 0 for failure.
670  
671     All arguments besides using are for the convenience of the routine;
672     they could be derived from the using array.  LAST_USING is a pair
673     of pointers to the last blocks in the using structure.  LOW_THREAD
674     and HIGH_THREAD tell which threads contain the lowest and highest
675     line numbers for File0.  LAST_DIFF3 contains the last diff produced
676     in the calling routine.  This is used for lines mappings that
677     would still be identical to the state that diff ended in.
678  
679     A distinction should be made in this routine between the two diffs
680     that are part of a normal two diff block, and the three diffs that
681     are part of a diff3_block.  */
682  
683  static struct diff3_block *
684  using_to_diff3_block (struct diff_block *using[2],
685  		      struct diff_block *last_using[2],
686  		      int low_thread, int high_thread,
687  		      struct diff3_block const *last_diff3)
688  {
689    lin low[2], high[2];
690    struct diff3_block *result;
691    struct diff_block *ptr;
692    int d;
693    lin i;
694  
695    /* Find the range in the common file.  */
696    lin lowc = D_LOWLINE (using[low_thread], FC);
697    lin highc = D_HIGHLINE (last_using[high_thread], FC);
698  
699    /* Find the ranges in the other files.
700       If using[d] is null, that means that the file to which that diff
701       refers is equivalent to the common file over this range.  */
702  
703    for (d = 0; d < 2; d++)
704      if (using[d])
705        {
706  	low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
707  	high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
708        }
709      else
710        {
711  	low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
712  	high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
713        }
714  
715    /* Create a block with the appropriate sizes */
716    result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
717  
718    /* Copy information for the common file.
719       Return with a zero if any of the compares failed.  */
720  
721    for (d = 0; d < 2; d++)
722      for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
723        {
724  	lin result_offset = D_LOWLINE (ptr, FC) - lowc;
725  
726  	if (!copy_stringlist (D_LINEARRAY (ptr, FC),
727  			      D_LENARRAY (ptr, FC),
728  			      D_LINEARRAY (result, FILEC) + result_offset,
729  			      D_LENARRAY (result, FILEC) + result_offset,
730  			      D_NUMLINES (ptr, FC)))
731  	  return 0;
732        }
733  
734    /* Copy information for file d.  First deal with anything that might be
735       before the first diff.  */
736  
737    for (d = 0; d < 2; d++)
738      {
739        struct diff_block *u = using[d];
740        lin lo = low[d], hi = high[d];
741  
742        for (i = 0;
743  	   i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
744  	   i++)
745  	{
746  	  D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
747  	  D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
748  	}
749  
750        for (ptr = u; ptr; ptr = D_NEXT (ptr))
751  	{
752  	  lin result_offset = D_LOWLINE (ptr, FO) - lo;
753  	  lin linec;
754  
755  	  if (!copy_stringlist (D_LINEARRAY (ptr, FO),
756  				D_LENARRAY (ptr, FO),
757  				D_LINEARRAY (result, FILE0 + d) + result_offset,
758  				D_LENARRAY (result, FILE0 + d) + result_offset,
759  				D_NUMLINES (ptr, FO)))
760  	    return 0;
761  
762  	  /* Catch the lines between here and the next diff */
763  	  linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
764  	  for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
765  	       i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
766  	       i++)
767  	    {
768  	      D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
769  	      D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
770  	      linec++;
771  	    }
772  	}
773      }
774  
775    /* Set correspond */
776    if (!using[0])
777      D3_TYPE (result) = DIFF_2ND;
778    else if (!using[1])
779      D3_TYPE (result) = DIFF_1ST;
780    else
781      {
782        lin nl0 = D_NUMLINES (result, FILE0);
783        lin nl1 = D_NUMLINES (result, FILE1);
784  
785        if (nl0 != nl1
786  	  || !compare_line_list (D_LINEARRAY (result, FILE0),
787  				 D_LENARRAY (result, FILE0),
788  				 D_LINEARRAY (result, FILE1),
789  				 D_LENARRAY (result, FILE1),
790  				 nl0))
791  	D3_TYPE (result) = DIFF_ALL;
792        else
793  	D3_TYPE (result) = DIFF_3RD;
794      }
795  
796    return result;
797  }
798  
799  /* Copy pointers from a list of strings to a different list of
800     strings.  If a spot in the second list is already filled, make sure
801     that it is filled with the same string; if not, return false, the copy
802     incomplete.  Upon successful completion of the copy, return true.  */
803  
804  static bool
805  copy_stringlist (char * const fromptrs[], size_t const fromlengths[],
806  		 char *toptrs[], size_t tolengths[],
807  		 lin copynum)
808  {
809    register char * const *f = fromptrs;
810    register char **t = toptrs;
811    register size_t const *fl = fromlengths;
812    register size_t *tl = tolengths;
813  
814    while (copynum--)
815      {
816        if (*t)
817  	{
818  	  if (*fl != *tl || memcmp (*f, *t, *fl) != 0)
819  	    return false;
820  	}
821        else
822  	{
823  	  *t = *f;
824  	  *tl = *fl;
825  	}
826  
827        t++; f++; tl++; fl++;
828      }
829  
830    return true;
831  }
832  
833  /* Create a diff3_block, with ranges as specified in the arguments.
834     Allocate the arrays for the various pointers (and zero them) based
835     on the arguments passed.  Return the block as a result.  */
836  
837  static struct diff3_block *
838  create_diff3_block (lin low0, lin high0,
839  		    lin low1, lin high1,
840  		    lin low2, lin high2)
841  {
842    struct diff3_block *result = xmalloc (sizeof *result);
843    lin numlines;
844  
845    D3_TYPE (result) = ERROR;
846    D_NEXT (result) = 0;
847  
848    /* Assign ranges */
849    D_LOWLINE (result, FILE0) = low0;
850    D_HIGHLINE (result, FILE0) = high0;
851    D_LOWLINE (result, FILE1) = low1;
852    D_HIGHLINE (result, FILE1) = high1;
853    D_LOWLINE (result, FILE2) = low2;
854    D_HIGHLINE (result, FILE2) = high2;
855  
856    /* Allocate and zero space */
857    numlines = D_NUMLINES (result, FILE0);
858    if (numlines)
859      {
860        D_LINEARRAY (result, FILE0) = xcalloc (numlines, sizeof (char *));
861        D_LENARRAY (result, FILE0) = xcalloc (numlines, sizeof (size_t));
862      }
863    else
864      {
865        D_LINEARRAY (result, FILE0) = 0;
866        D_LENARRAY (result, FILE0) = 0;
867      }
868  
869    numlines = D_NUMLINES (result, FILE1);
870    if (numlines)
871      {
872        D_LINEARRAY (result, FILE1) = xcalloc (numlines, sizeof (char *));
873        D_LENARRAY (result, FILE1) = xcalloc (numlines, sizeof (size_t));
874      }
875    else
876      {
877        D_LINEARRAY (result, FILE1) = 0;
878        D_LENARRAY (result, FILE1) = 0;
879      }
880  
881    numlines = D_NUMLINES (result, FILE2);
882    if (numlines)
883      {
884        D_LINEARRAY (result, FILE2) = xcalloc (numlines, sizeof (char *));
885        D_LENARRAY (result, FILE2) = xcalloc (numlines, sizeof (size_t));
886      }
887    else
888      {
889        D_LINEARRAY (result, FILE2) = 0;
890        D_LENARRAY (result, FILE2) = 0;
891      }
892  
893    /* Return */
894    return result;
895  }
896  
897  /* Compare two lists of lines of text.
898     Return 1 if they are equivalent, 0 if not.  */
899  
900  static bool
901  compare_line_list (char * const list1[], size_t const lengths1[],
902  		   char * const list2[], size_t const lengths2[],
903  		   lin nl)
904  {
905    char * const *l1 = list1;
906    char * const *l2 = list2;
907    size_t const *lgths1 = lengths1;
908    size_t const *lgths2 = lengths2;
909  
910    while (nl--)
911      if (!*l1 || !*l2 || *lgths1 != *lgths2++
912  	|| memcmp (*l1++, *l2++, *lgths1++) != 0)
913        return false;
914    return true;
915  }
916  
917  /* Input and parse two way diffs.  */
918  
919  static struct diff_block *
920  process_diff (char const *filea,
921  	      char const *fileb,
922  	      struct diff_block **last_block)
923  {
924    char *diff_contents;
925    char *diff_limit;
926    char *scan_diff;
927    enum diff_type dt;
928    lin i;
929    struct diff_block *block_list, **block_list_end, *bptr;
930    size_t too_many_lines = (PTRDIFF_MAX
931  			   / MIN (sizeof *bptr->lines[1],
932  				  sizeof *bptr->lengths[1]));
933  
934    diff_limit = read_diff (filea, fileb, &diff_contents);
935    scan_diff = diff_contents;
936    block_list_end = &block_list;
937    bptr = 0; /* Pacify `gcc -W'.  */
938  
939    while (scan_diff < diff_limit)
940      {
941        bptr = xmalloc (sizeof *bptr);
942        bptr->lines[0] = bptr->lines[1] = 0;
943        bptr->lengths[0] = bptr->lengths[1] = 0;
944  
945        dt = process_diff_control (&scan_diff, bptr);
946        if (dt == ERROR || *scan_diff != '\n')
947  	{
948  	  fprintf (stderr, _("%s: diff failed: "), program_name);
949  	  do
950  	    {
951  	      putc (*scan_diff, stderr);
952  	    }
953  	  while (*scan_diff++ != '\n');
954  	  exit (EXIT_TROUBLE);
955  	}
956        scan_diff++;
957  
958        /* Force appropriate ranges to be null, if necessary */
959        switch (dt)
960  	{
961  	case ADD:
962  	  bptr->ranges[0][0]++;
963  	  break;
964  	case DELETE:
965  	  bptr->ranges[1][0]++;
966  	  break;
967  	case CHANGE:
968  	  break;
969  	default:
970  	  fatal ("internal error: invalid diff type in process_diff");
971  	  break;
972  	}
973  
974        /* Allocate space for the pointers for the lines from filea, and
975  	 parcel them out among these pointers */
976        if (dt != ADD)
977  	{
978  	  lin numlines = D_NUMLINES (bptr, 0);
979  	  if (too_many_lines <= numlines)
980  	    xalloc_die ();
981  	  bptr->lines[0] = xmalloc (numlines * sizeof *bptr->lines[0]);
982  	  bptr->lengths[0] = xmalloc (numlines * sizeof *bptr->lengths[0]);
983  	  for (i = 0; i < numlines; i++)
984  	    scan_diff = scan_diff_line (scan_diff,
985  					&(bptr->lines[0][i]),
986  					&(bptr->lengths[0][i]),
987  					diff_limit,
988  					'<');
989  	}
990  
991        /* Get past the separator for changes */
992        if (dt == CHANGE)
993  	{
994  	  if (strncmp (scan_diff, "---\n", 4))
995  	    fatal ("invalid diff format; invalid change separator");
996  	  scan_diff += 4;
997  	}
998  
999        /* Allocate space for the pointers for the lines from fileb, and
1000  	 parcel them out among these pointers */
1001        if (dt != DELETE)
1002  	{
1003  	  lin numlines = D_NUMLINES (bptr, 1);
1004  	  if (too_many_lines <= numlines)
1005  	    xalloc_die ();
1006  	  bptr->lines[1] = xmalloc (numlines * sizeof *bptr->lines[1]);
1007  	  bptr->lengths[1] = xmalloc (numlines * sizeof *bptr->lengths[1]);
1008  	  for (i = 0; i < numlines; i++)
1009  	    scan_diff = scan_diff_line (scan_diff,
1010  					&(bptr->lines[1][i]),
1011  					&(bptr->lengths[1][i]),
1012  					diff_limit,
1013  					'>');
1014  	}
1015  
1016        /* Place this block on the blocklist.  */
1017        *block_list_end = bptr;
1018        block_list_end = &bptr->next;
1019      }
1020  
1021    *block_list_end = 0;
1022    *last_block = bptr;
1023    return block_list;
1024  }
1025  
1026  /* Skip tabs and spaces, and return the first character after them.  */
1027  
1028  static char *
1029  skipwhite (char *s)
1030  {
1031    while (*s == ' ' || *s == '\t')
1032      s++;
1033    return s;
1034  }
1035  
1036  /* Read a nonnegative line number from S, returning the address of the
1037     first character after the line number, and storing the number into
1038     *PNUM.  Return 0 if S does not point to a valid line number.  */
1039  
1040  static char *
1041  readnum (char *s, lin *pnum)
1042  {
1043    unsigned char c = *s;
1044    lin num = 0;
1045  
1046    if (! ISDIGIT (c))
1047      return 0;
1048  
1049    do
1050      {
1051        num = c - '0' + num * 10;
1052        c = *++s;
1053      }
1054    while (ISDIGIT (c));
1055  
1056    *pnum = num;
1057    return s;
1058  }
1059  
1060  /* Parse a normal format diff control string.  Return the type of the
1061     diff (ERROR if the format is bad).  All of the other important
1062     information is filled into to the structure pointed to by db, and
1063     the string pointer (whose location is passed to this routine) is
1064     updated to point beyond the end of the string parsed.  Note that
1065     only the ranges in the diff_block will be set by this routine.
1066  
1067     If some specific pair of numbers has been reduced to a single
1068     number, then both corresponding numbers in the diff block are set
1069     to that number.  In general these numbers are interpreted as ranges
1070     inclusive, unless being used by the ADD or DELETE commands.  It is
1071     assumed that these will be special cased in a superior routine.   */
1072  
1073  static enum diff_type
1074  process_diff_control (char **string, struct diff_block *db)
1075  {
1076    char *s = *string;
1077    enum diff_type type;
1078  
1079    /* Read first set of digits */
1080    s = readnum (skipwhite (s), &db->ranges[0][RANGE_START]);
1081    if (! s)
1082      return ERROR;
1083  
1084    /* Was that the only digit? */
1085    s = skipwhite (s);
1086    if (*s == ',')
1087      {
1088        s = readnum (s + 1, &db->ranges[0][RANGE_END]);
1089        if (! s)
1090  	return ERROR;
1091      }
1092    else
1093      db->ranges[0][RANGE_END] = db->ranges[0][RANGE_START];
1094  
1095    /* Get the letter */
1096    s = skipwhite (s);
1097    switch (*s)
1098      {
1099      case 'a':
1100        type = ADD;
1101        break;
1102      case 'c':
1103        type = CHANGE;
1104        break;
1105      case 'd':
1106        type = DELETE;
1107        break;
1108      default:
1109        return ERROR;			/* Bad format */
1110      }
1111    s++;				/* Past letter */
1112  
1113    /* Read second set of digits */
1114    s = readnum (skipwhite (s), &db->ranges[1][RANGE_START]);
1115    if (! s)
1116      return ERROR;
1117  
1118    /* Was that the only digit? */
1119    s = skipwhite (s);
1120    if (*s == ',')
1121      {
1122        s = readnum (s + 1, &db->ranges[1][RANGE_END]);
1123        if (! s)
1124  	return ERROR;
1125        s = skipwhite (s);		/* To move to end */
1126      }
1127    else
1128      db->ranges[1][RANGE_END] = db->ranges[1][RANGE_START];
1129  
1130    *string = s;
1131    return type;
1132  }
1133  
1134  static char *
1135  read_diff (char const *filea,
1136  	   char const *fileb,
1137  	   char **output_placement)
1138  {
1139    char *diff_result;
1140    size_t current_chunk_size, total;
1141    int fd, wstatus, status;
1142    int werrno = 0;
1143    struct stat pipestat;
1144  
1145  #if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
1146  
1147    char const *argv[9];
1148    char const **ap;
1149    int fds[2];
1150    pid_t pid;
1151  
1152    ap = argv;
1153    *ap++ = diff_program;
1154    if (text)
1155      *ap++ = "-a";
1156    if (strip_trailing_cr)
1157      *ap++ = "--strip-trailing-cr";
1158    *ap++ = "--horizon-lines=100";
1159    *ap++ = "--";
1160    *ap++ = filea;
1161    *ap++ = fileb;
1162    *ap = 0;
1163  
1164    if (pipe (fds) != 0)
1165      perror_with_exit ("pipe");
1166  
1167    pid = vfork ();
1168    if (pid == 0)
1169      {
1170        /* Child */
1171        close (fds[0]);
1172        if (fds[1] != STDOUT_FILENO)
1173  	{
1174  	  dup2 (fds[1], STDOUT_FILENO);
1175  	  close (fds[1]);
1176  	}
1177  
1178        /* The cast to (char **) is needed for portability to older
1179  	 hosts with a nonstandard prototype for execvp.  */
1180        execvp (diff_program, (char **) argv);
1181  
1182        _exit (errno == ENOENT ? 127 : 126);
1183      }
1184  
1185    if (pid == -1)
1186      perror_with_exit ("fork");
1187  
1188    close (fds[1]);		/* Prevent erroneous lack of EOF */
1189    fd = fds[0];
1190  
1191  #else
1192  
1193    FILE *fpipe;
1194    char const args[] = " --horizon-lines=100 -- ";
1195    char *command = xmalloc (quote_system_arg (0, diff_program)
1196  			   + sizeof "-a"
1197  			   + sizeof "--strip-trailing-cr"
1198  			   + sizeof args - 1
1199  			   + quote_system_arg (0, filea) + 1
1200  			   + quote_system_arg (0, fileb) + 1);
1201    char *p = command;
1202    p += quote_system_arg (p, diff_program);
1203    if (text)
1204      {
1205        strcpy (p, " -a");
1206        p += 3;
1207      }
1208    if (strip_trailing_cr)
1209      {
1210        strcpy (p, " --strip-trailing-cr");
1211        p += 20;
1212      }
1213    strcpy (p, args);
1214    p += sizeof args - 1;
1215    p += quote_system_arg (p, filea);
1216    *p++ = ' ';
1217    p += quote_system_arg (p, fileb);
1218    *p = 0;
1219    errno = 0;
1220    fpipe = popen (command, "r");
1221    if (!fpipe)
1222      perror_with_exit (command);
1223    free (command);
1224    fd = fileno (fpipe);
1225  
1226  #endif
1227  
1228    if (fstat (fd, &pipestat) != 0)
1229      perror_with_exit ("fstat");
1230    current_chunk_size = MAX (1, STAT_BLOCKSIZE (pipestat));
1231    diff_result = xmalloc (current_chunk_size);
1232    total = 0;
1233  
1234    for (;;)
1235      {
1236        size_t bytes_to_read = current_chunk_size - total;
1237        size_t bytes = block_read (fd, diff_result + total, bytes_to_read);
1238        total += bytes;
1239        if (bytes != bytes_to_read)
1240  	{
1241  	  if (bytes == SIZE_MAX)
1242  	    perror_with_exit (_("read failed"));
1243  	  break;
1244  	}
1245        if (PTRDIFF_MAX / 2 <= current_chunk_size)
1246  	xalloc_die ();
1247        current_chunk_size *= 2;
1248        diff_result = xrealloc (diff_result, current_chunk_size);
1249      }
1250  
1251    if (total != 0 && diff_result[total-1] != '\n')
1252      fatal ("invalid diff format; incomplete last line");
1253  
1254    *output_placement = diff_result;
1255  
1256  #if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
1257  
1258    wstatus = pclose (fpipe);
1259    if (wstatus == -1)
1260      werrno = errno;
1261  
1262  #else
1263  
1264    if (close (fd) != 0)
1265      perror_with_exit ("close");
1266    if (waitpid (pid, &wstatus, 0) < 0)
1267      perror_with_exit ("waitpid");
1268  
1269  #endif
1270  
1271    status = ! werrno && WIFEXITED (wstatus) ? WEXITSTATUS (wstatus) : INT_MAX;
1272  
1273    if (EXIT_TROUBLE <= status)
1274      error (EXIT_TROUBLE, werrno,
1275  	   _(status == 126
1276  	     ? "subsidiary program `%s' could not be invoked"
1277  	     : status == 127
1278  	     ? "subsidiary program `%s' not found"
1279  	     : status == INT_MAX
1280  	     ? "subsidiary program `%s' failed"
1281  	     : "subsidiary program `%s' failed (exit status %d)"),
1282  	   diff_program, status);
1283  
1284    return diff_result + total;
1285  }
1286  
1287  
1288  /* Scan a regular diff line (consisting of > or <, followed by a
1289     space, followed by text (including nulls) up to a newline.
1290  
1291     This next routine began life as a macro and many parameters in it
1292     are used as call-by-reference values.  */
1293  static char *
1294  scan_diff_line (char *scan_ptr, char **set_start, size_t *set_length,
1295  		char *limit, char leadingchar)
1296  {
1297    char *line_ptr;
1298  
1299    if (!(scan_ptr[0] == leadingchar
1300  	&& scan_ptr[1] == ' '))
1301      fatal ("invalid diff format; incorrect leading line chars");
1302  
1303    *set_start = line_ptr = scan_ptr + 2;
1304    while (*line_ptr++ != '\n')
1305      continue;
1306  
1307    /* Include newline if the original line ended in a newline,
1308       or if an edit script is being generated.
1309       Copy any missing newline message to stderr if an edit script is being
1310       generated, because edit scripts cannot handle missing newlines.
1311       Return the beginning of the next line.  */
1312    *set_length = line_ptr - *set_start;
1313    if (line_ptr < limit && *line_ptr == '\\')
1314      {
1315        if (edscript)
1316  	fprintf (stderr, "%s:", program_name);
1317        else
1318  	--*set_length;
1319        line_ptr++;
1320        do
1321  	{
1322  	  if (edscript)
1323  	    putc (*line_ptr, stderr);
1324  	}
1325        while (*line_ptr++ != '\n');
1326      }
1327  
1328    return line_ptr;
1329  }
1330  
1331  /* Output a three way diff passed as a list of diff3_block's.  The
1332     argument MAPPING is indexed by external file number (in the
1333     argument list) and contains the internal file number (from the diff
1334     passed).  This is important because the user expects outputs in
1335     terms of the argument list number, and the diff passed may have
1336     been done slightly differently (if the last argument was "-", for
1337     example).  REV_MAPPING is the inverse of MAPPING.  */
1338  
1339  static void
1340  output_diff3 (FILE *outputfile, struct diff3_block *diff,
1341  	      int const mapping[3], int const rev_mapping[3])
1342  {
1343    int i;
1344    int oddoneout;
1345    char *cp;
1346    struct diff3_block *ptr;
1347    lin line;
1348    size_t length;
1349    int dontprint;
1350    static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
1351    char const *line_prefix = initial_tab ? "\t" : "  ";
1352  
1353    for (ptr = diff; ptr; ptr = D_NEXT (ptr))
1354      {
1355        char x[2];
1356  
1357        switch (ptr->correspond)
1358  	{
1359  	case DIFF_ALL:
1360  	  x[0] = 0;
1361  	  dontprint = 3;	/* Print them all */
1362  	  oddoneout = 3;	/* Nobody's odder than anyone else */
1363  	  break;
1364  	case DIFF_1ST:
1365  	case DIFF_2ND:
1366  	case DIFF_3RD:
1367  	  oddoneout = rev_mapping[ptr->correspond - DIFF_1ST];
1368  
1369  	  x[0] = oddoneout + '1';
1370  	  x[1] = 0;
1371  	  dontprint = oddoneout == 0;
1372  	  break;
1373  	default:
1374  	  fatal ("internal error: invalid diff type passed to output");
1375  	}
1376        fprintf (outputfile, "====%s\n", x);
1377  
1378        /* Go 0, 2, 1 if the first and third outputs are equivalent.  */
1379        for (i = 0; i < 3;
1380  	   i = (oddoneout == 1 ? skew_increment[i] : i + 1))
1381  	{
1382  	  int realfile = mapping[i];
1383  	  lin lowt = D_LOWLINE (ptr, realfile);
1384  	  lin hight = D_HIGHLINE (ptr, realfile);
1385  	  long int llowt = lowt;
1386  	  long int lhight = hight;
1387  
1388  	  fprintf (outputfile, "%d:", i + 1);
1389  	  switch (lowt - hight)
1390  	    {
1391  	    case 1:
1392  	      fprintf (outputfile, "%lda\n", llowt - 1);
1393  	      break;
1394  	    case 0:
1395  	      fprintf (outputfile, "%ldc\n", llowt);
1396  	      break;
1397  	    default:
1398  	      fprintf (outputfile, "%ld,%ldc\n", llowt, lhight);
1399  	      break;
1400  	    }
1401  
1402  	  if (i == dontprint) continue;
1403  
1404  	  if (lowt <= hight)
1405  	    {
1406  	      line = 0;
1407  	      do
1408  		{
1409  		  fprintf (outputfile, line_prefix);
1410  		  cp = D_RELNUM (ptr, realfile, line);
1411  		  length = D_RELLEN (ptr, realfile, line);
1412  		  fwrite (cp, sizeof (char), length, outputfile);
1413  		}
1414  	      while (++line < hight - lowt + 1);
1415  	      if (cp[length - 1] != '\n')
1416  		fprintf (outputfile, "\n\\ %s\n",
1417  			 _("No newline at end of file"));
1418  	    }
1419  	}
1420      }
1421  }
1422  
1423  
1424  /* Output to OUTPUTFILE the lines of B taken from FILENUM.  Double any
1425     initial '.'s; yield nonzero if any initial '.'s were doubled.  */
1426  
1427  static bool
1428  dotlines (FILE *outputfile, struct diff3_block *b, int filenum)
1429  {
1430    lin i;
1431    bool leading_dot = false;
1432  
1433    for (i = 0;
1434         i < D_NUMLINES (b, filenum);
1435         i++)
1436      {
1437        char *line = D_RELNUM (b, filenum, i);
1438        if (line[0] == '.')
1439  	{
1440  	  leading_dot = true;
1441  	  fprintf (outputfile, ".");
1442  	}
1443        fwrite (line, sizeof (char),
1444  	      D_RELLEN (b, filenum, i), outputfile);
1445      }
1446  
1447    return leading_dot;
1448  }
1449  
1450  /* Output to OUTPUTFILE a '.' line.  If LEADING_DOT is true, also
1451     output a command that removes initial '.'s starting with line START
1452     and continuing for NUM lines.  (START is long int, not lin, for
1453     convenience with printf %ld formats.)  */
1454  
1455  static void
1456  undotlines (FILE *outputfile, bool leading_dot, long int start, lin num)
1457  {
1458    fprintf (outputfile, ".\n");
1459    if (leading_dot)
1460      {
1461        if (num == 1)
1462  	fprintf (outputfile, "%lds/^\\.//\n", start);
1463        else
1464  	fprintf (outputfile, "%ld,%lds/^\\.//\n", start, start + num - 1);
1465      }
1466  }
1467  
1468  /* Output a diff3 set of blocks as an ed script.  This script applies
1469     the changes between file's 2 & 3 to file 1.  Take the precise
1470     format of the ed script to be output from global variables set
1471     during options processing.  Reverse the order of
1472     the set of diff3 blocks in DIFF; this gets
1473     around the problems involved with changing line numbers in an ed
1474     script.
1475  
1476     As in `output_diff3', the variable MAPPING maps from file number
1477     according to the argument list to file number according to the diff
1478     passed.  All files listed below are in terms of the argument list.
1479     REV_MAPPING is the inverse of MAPPING.
1480  
1481     FILE0, FILE1 and FILE2 are the strings to print as the names of the
1482     three files.  These may be the actual names, or may be the
1483     arguments specified with -L.
1484  
1485     Return 1 if conflicts were found.  */
1486  
1487  static bool
1488  output_diff3_edscript (FILE *outputfile, struct diff3_block *diff,
1489  		       int const mapping[3], int const rev_mapping[3],
1490  		       char const *file0, char const *file1, char const *file2)
1491  {
1492    bool leading_dot;
1493    bool conflicts_found = false;
1494    bool conflict;
1495    struct diff3_block *b;
1496  
1497    for (b = reverse_diff3_blocklist (diff); b; b = b->next)
1498      {
1499        /* Must do mapping correctly.  */
1500        enum diff_type type
1501  	= (b->correspond == DIFF_ALL
1502  	   ? DIFF_ALL
1503  	   : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
1504  
1505        long int low0, high0;
1506  
1507        /* If we aren't supposed to do this output block, skip it.  */
1508        switch (type)
1509  	{
1510  	default: continue;
1511  	case DIFF_2ND: if (!show_2nd) continue; conflict = true; break;
1512  	case DIFF_3RD: if (overlap_only) continue; conflict = false; break;
1513  	case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
1514  	}
1515  
1516        low0 = D_LOWLINE (b, mapping[FILE0]);
1517        high0 = D_HIGHLINE (b, mapping[FILE0]);
1518  
1519        if (conflict)
1520  	{
1521  	  conflicts_found = true;
1522  
1523  
1524  	  /* Mark end of conflict.  */
1525  
1526  	  fprintf (outputfile, "%lda\n", high0);
1527  	  leading_dot = false;
1528  	  if (type == DIFF_ALL)
1529  	    {
1530  	      if (show_2nd)
1531  		{
1532  		  /* Append lines from FILE1.  */
1533  		  fprintf (outputfile, "||||||| %s\n", file1);
1534  		  leading_dot = dotlines (outputfile, b, mapping[FILE1]);
1535  		}
1536  	      /* Append lines from FILE2.  */
1537  	      fprintf (outputfile, "=======\n");
1538  	      leading_dot |= dotlines (outputfile, b, mapping[FILE2]);
1539  	    }
1540  	  fprintf (outputfile, ">>>>>>> %s\n", file2);
1541  	  undotlines (outputfile, leading_dot, high0 + 2,
1542  		      (D_NUMLINES (b, mapping[FILE1])
1543  		       + D_NUMLINES (b, mapping[FILE2]) + 1));
1544  
1545  
1546  	  /* Mark start of conflict.  */
1547  
1548  	  fprintf (outputfile, "%lda\n<<<<<<< %s\n", low0 - 1,
1549  		   type == DIFF_ALL ? file0 : file1);
1550  	  leading_dot = false;
1551  	  if (type == DIFF_2ND)
1552  	    {
1553  	      /* Prepend lines from FILE1.  */
1554  	      leading_dot = dotlines (outputfile, b, mapping[FILE1]);
1555  	      fprintf (outputfile, "=======\n");
1556  	    }
1557  	  undotlines (outputfile, leading_dot, low0 + 1,
1558  		      D_NUMLINES (b, mapping[FILE1]));
1559  	}
1560        else if (D_NUMLINES (b, mapping[FILE2]) == 0)
1561  	/* Write out a delete */
1562  	{
1563  	  if (low0 == high0)
1564  	    fprintf (outputfile, "%ldd\n", low0);
1565  	  else
1566  	    fprintf (outputfile, "%ld,%ldd\n", low0, high0);
1567  	}
1568        else
1569  	/* Write out an add or change */
1570  	{
1571  	  switch (high0 - low0)
1572  	    {
1573  	    case -1:
1574  	      fprintf (outputfile, "%lda\n", high0);
1575  	      break;
1576  	    case 0:
1577  	      fprintf (outputfile, "%ldc\n", high0);
1578  	      break;
1579  	    default:
1580  	      fprintf (outputfile, "%ld,%ldc\n", low0, high0);
1581  	      break;
1582  	    }
1583  
1584  	  undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]),
1585  		      low0, D_NUMLINES (b, mapping[FILE2]));
1586  	}
1587      }
1588    if (finalwrite) fprintf (outputfile, "w\nq\n");
1589    return conflicts_found;
1590  }
1591  
1592  /* Read from INFILE and output to OUTPUTFILE a set of diff3_blocks
1593     DIFF as a merged file.  This acts like 'ed file0
1594     <[output_diff3_edscript]', except that it works even for binary
1595     data or incomplete lines.
1596  
1597     As before, MAPPING maps from arg list file number to diff file
1598     number, REV_MAPPING is its inverse, and FILE0, FILE1, and FILE2 are
1599     the names of the files.
1600  
1601     Return 1 if conflicts were found.  */
1602  
1603  static bool
1604  output_diff3_merge (FILE *infile, FILE *outputfile, struct diff3_block *diff,
1605  		    int const mapping[3], int const rev_mapping[3],
1606  		    char const *file0, char const *file1, char const *file2)
1607  {
1608    int c;
1609    lin i;
1610    bool conflicts_found = false;
1611    bool conflict;
1612    struct diff3_block *b;
1613    lin linesread = 0;
1614  
1615    for (b = diff; b; b = b->next)
1616      {
1617        /* Must do mapping correctly.  */
1618        enum diff_type type
1619  	= ((b->correspond == DIFF_ALL)
1620  	   ? DIFF_ALL
1621  	   : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
1622        char const *format_2nd = "<<<<<<< %s\n";
1623  
1624        /* If we aren't supposed to do this output block, skip it.  */
1625        switch (type)
1626  	{
1627  	default: continue;
1628  	case DIFF_2ND: if (!show_2nd) continue; conflict = true; break;
1629  	case DIFF_3RD: if (overlap_only) continue; conflict = false; break;
1630  	case DIFF_ALL: if (simple_only) continue; conflict = flagging;
1631  	  format_2nd = "||||||| %s\n";
1632  	  break;
1633  	}
1634  
1635        /* Copy I lines from file 0.  */
1636        i = D_LOWLINE (b, FILE0) - linesread - 1;
1637        linesread += i;
1638        while (0 <= --i)
1639  	do
1640  	  {
1641  	    c = getc (infile);
1642  	    if (c == EOF)
1643  	      {
1644  		if (ferror (infile))
1645  		  perror_with_exit (_("read failed"));
1646  		else if (feof (infile))
1647  		  fatal ("input file shrank");
1648  	      }
1649  	    putc (c, outputfile);
1650  	  }
1651  	while (c != '\n');
1652  
1653        if (conflict)
1654  	{
1655  	  conflicts_found = true;
1656  
1657  	  if (type == DIFF_ALL)
1658  	    {
1659  	      /* Put in lines from FILE0 with bracket.  */
1660  	      fprintf (outputfile, "<<<<<<< %s\n", file0);
1661  	      for (i = 0;
1662  		   i < D_NUMLINES (b, mapping[FILE0]);
1663  		   i++)
1664  		fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
1665  			D_RELLEN (b, mapping[FILE0], i), outputfile);
1666  	    }
1667  
1668  	  if (show_2nd)
1669  	    {
1670  	      /* Put in lines from FILE1 with bracket.  */
1671  	      fprintf (outputfile, format_2nd, file1);
1672  	      for (i = 0;
1673  		   i < D_NUMLINES (b, mapping[FILE1]);
1674  		   i++)
1675  		fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char),
1676  			D_RELLEN (b, mapping[FILE1], i), outputfile);
1677  	    }
1678  
1679  	  fprintf (outputfile, "=======\n");
1680  	}
1681  
1682        /* Put in lines from FILE2.  */
1683        for (i = 0;
1684  	   i < D_NUMLINES (b, mapping[FILE2]);
1685  	   i++)
1686  	fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
1687  		D_RELLEN (b, mapping[FILE2], i), outputfile);
1688  
1689        if (conflict)
1690  	fprintf (outputfile, ">>>>>>> %s\n", file2);
1691  
1692        /* Skip I lines in file 0.  */
1693        i = D_NUMLINES (b, FILE0);
1694        linesread += i;
1695        while (0 <= --i)
1696  	while ((c = getc (infile)) != '\n')
1697  	  if (c == EOF)
1698  	    {
1699  	      if (ferror (infile))
1700  		perror_with_exit (_("read failed"));
1701  	      else if (feof (infile))
1702  		{
1703  		  if (i || b->next)
1704  		    fatal ("input file shrank");
1705  		  return conflicts_found;
1706  		}
1707  	    }
1708      }
1709    /* Copy rest of common file.  */
1710    while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
1711      putc (c, outputfile);
1712    return conflicts_found;
1713  }
1714  
1715  /* Reverse the order of the list of diff3 blocks.  */
1716  
1717  static struct diff3_block *
1718  reverse_diff3_blocklist (struct diff3_block *diff)
1719  {
1720    register struct diff3_block *tmp, *next, *prev;
1721  
1722    for (tmp = diff, prev = 0;  tmp;  tmp = next)
1723      {
1724        next = tmp->next;
1725        tmp->next = prev;
1726        prev = tmp;
1727      }
1728  
1729    return prev;
1730  }
1731  
1732  static void
1733  fatal (char const *msgid)
1734  {
1735    error (EXIT_TROUBLE, 0, "%s", _(msgid));
1736    abort ();
1737  }
1738  
1739  static void
1740  perror_with_exit (char const *string)
1741  {
1742    error (EXIT_TROUBLE, errno, "%s", string);
1743    abort ();
1744  }
1745