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