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