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
59enum 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 */
71struct 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
80struct 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.  */
131static bool text;
132
133/* Remove trailing carriage returns from input.  */
134static bool strip_trailing_cr;
135
136/* If nonzero, write out an ed script instead of the standard diff3 format.  */
137static 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.  */
142static bool flagging;
143
144/* Use a tab to align output lines (-T).  */
145static bool initial_tab;
146
147/* If nonzero, do not output information for overlapping diffs.  */
148static bool simple_only;
149
150/* If nonzero, do not output information for non-overlapping diffs.  */
151static bool overlap_only;
152
153/* If nonzero, show information for DIFF_2ND diffs.  */
154static bool show_2nd;
155
156/* If nonzero, include `:wq' at the end of the script
157   to write out the file being edited.   */
158static bool finalwrite;
159
160/* If nonzero, output a merged file.  */
161static bool merge;
162
163char *program_name;
164
165static char *read_diff (char const *, char const *, char **);
166static char *scan_diff_line (char *, char **, size_t *, char *, char);
167static enum diff_type process_diff_control (char **, struct diff_block *);
168static bool compare_line_list (char * const[], size_t const[], char * const[], size_t const[], lin);
169static bool copy_stringlist (char * const[], size_t const[], char *[], size_t[], lin);
170static bool output_diff3_edscript (FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
171static bool output_diff3_merge (FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
172static struct diff3_block *create_diff3_block (lin, lin, lin, lin, lin, lin);
173static struct diff3_block *make_3way_diff (struct diff_block *, struct diff_block *);
174static struct diff3_block *reverse_diff3_blocklist (struct diff3_block *);
175static struct diff3_block *using_to_diff3_block (struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *);
176static struct diff_block *process_diff (char const *, char const *, struct diff_block **);
177static void check_stdout (void);
178static void fatal (char const *) __attribute__((noreturn));
179static void output_diff3 (FILE *, struct diff3_block *, int const[3], int const[3]);
180static void perror_with_exit (char const *) __attribute__((noreturn));
181static void try_help (char const *, char const *) __attribute__((noreturn));
182static void usage (void);
183
184static char const *diff_program = DEFAULT_DIFF_PROGRAM;
185
186/* Values for long options that do not have single-letter equivalents.  */
187enum
188{
189  DIFF_PROGRAM_OPTION = CHAR_MAX + 1,
190  HELP_OPTION,
191  STRIP_TRAILING_CR_OPTION
192};
193
194static 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
212int
213main (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
405static void
406try_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
415static void
416check_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
424static 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
445static void
446usage (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
519static struct diff3_block *
520make_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
682static struct diff3_block *
683using_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
803static bool
804copy_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
836static struct diff3_block *
837create_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
899static bool
900compare_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
918static struct diff_block *
919process_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
1027static char *
1028skipwhite (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
1039static char *
1040readnum (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
1072static enum diff_type
1073process_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
1133static char *
1134read_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.  */
1292static char *
1293scan_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
1338static void
1339output_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
1426static bool
1427dotlines (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
1454static void
1455undotlines (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
1486static bool
1487output_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
1602static bool
1603output_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
1716static struct diff3_block *
1717reverse_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
1731static void
1732fatal (char const *msgid)
1733{
1734  error (EXIT_TROUBLE, 0, "%s", _(msgid));
1735  abort ();
1736}
1737
1738static void
1739perror_with_exit (char const *string)
1740{
1741  error (EXIT_TROUBLE, errno, "%s", string);
1742  abort ();
1743}
1744