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