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