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