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