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