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