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