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