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