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