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