amd64 port: mainly on the pmap headers, identify_cpu and initcpu
[dragonfly/port-amd64.git] / contrib / diffutils-2.8 / src / diff3.c
blob261eeabfdfb18b6399e443ffa4cd95f8006563f1
1 /* diff3 - compare three files line by line
3 Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1998, 2001,
4 2002, 2004 Free Software Foundation, Inc.
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.
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.
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. */
21 #include "system.h"
22 #include "paths.h"
24 #include <stdio.h>
25 #include <unlocked-io.h>
27 #include <c-stack.h>
28 #include <cmpbuf.h>
29 #include <error.h>
30 #include <exitfail.h>
31 #include <file-type.h>
32 #include <getopt.h>
33 #include <inttostr.h>
34 #include <quotesys.h>
35 #include <version-etc.h>
36 #include <xalloc.h>
38 /* Internal data structures and macros for the diff3 program; includes
39 data structures for both diff3 diffs and normal diffs. */
41 /* Different files within a three way diff. */
42 #define FILE0 0
43 #define FILE1 1
44 #define FILE2 2
46 /* A three way diff is built from two two-way diffs; the file which
47 the two two-way diffs share is: */
48 #define FILEC FILE2
50 /* Different files within a two way diff.
51 FC is the common file, FO the other file. */
52 #define FO 0
53 #define FC 1
55 /* The ranges are indexed by */
56 #define RANGE_START 0
57 #define RANGE_END 1
59 enum diff_type {
60 ERROR, /* Should not be used */
61 ADD, /* Two way diff add */
62 CHANGE, /* Two way diff change */
63 DELETE, /* Two way diff delete */
64 DIFF_ALL, /* All three are different */
65 DIFF_1ST, /* Only the first is different */
66 DIFF_2ND, /* Only the second */
67 DIFF_3RD /* Only the third */
70 /* Two way diff */
71 struct diff_block {
72 lin ranges[2][2]; /* Ranges are inclusive */
73 char **lines[2]; /* The actual lines (may contain nulls) */
74 size_t *lengths[2]; /* Line lengths (including newlines, if any) */
75 struct diff_block *next;
78 /* Three way diff */
80 struct diff3_block {
81 enum diff_type correspond; /* Type of diff */
82 lin ranges[3][2]; /* Ranges are inclusive */
83 char **lines[3]; /* The actual lines (may contain nulls) */
84 size_t *lengths[3]; /* Line lengths (including newlines, if any) */
85 struct diff3_block *next;
88 /* Access the ranges on a diff block. */
89 #define D_LOWLINE(diff, filenum) \
90 ((diff)->ranges[filenum][RANGE_START])
91 #define D_HIGHLINE(diff, filenum) \
92 ((diff)->ranges[filenum][RANGE_END])
93 #define D_NUMLINES(diff, filenum) \
94 (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
96 /* Access the line numbers in a file in a diff by relative line
97 numbers (i.e. line number within the diff itself). Note that these
98 are lvalues and can be used for assignment. */
99 #define D_RELNUM(diff, filenum, linenum) \
100 ((diff)->lines[filenum][linenum])
101 #define D_RELLEN(diff, filenum, linenum) \
102 ((diff)->lengths[filenum][linenum])
104 /* And get at them directly, when that should be necessary. */
105 #define D_LINEARRAY(diff, filenum) \
106 ((diff)->lines[filenum])
107 #define D_LENARRAY(diff, filenum) \
108 ((diff)->lengths[filenum])
110 /* Next block. */
111 #define D_NEXT(diff) ((diff)->next)
113 /* Access the type of a diff3 block. */
114 #define D3_TYPE(diff) ((diff)->correspond)
116 /* Line mappings based on diffs. The first maps off the top of the
117 diff, the second off of the bottom. */
118 #define D_HIGH_MAPLINE(diff, fromfile, tofile, linenum) \
119 ((linenum) \
120 - D_HIGHLINE ((diff), (fromfile)) \
121 + D_HIGHLINE ((diff), (tofile)))
123 #define D_LOW_MAPLINE(diff, fromfile, tofile, linenum) \
124 ((linenum) \
125 - D_LOWLINE ((diff), (fromfile)) \
126 + D_LOWLINE ((diff), (tofile)))
128 /* Options variables for flags set on command line. */
130 /* If nonzero, treat all files as text files, never as binary. */
131 static bool text;
133 /* Remove trailing carriage returns from input. */
134 static bool strip_trailing_cr;
136 /* If nonzero, write out an ed script instead of the standard diff3 format. */
137 static bool edscript;
139 /* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
140 preserve the lines which would normally be deleted from
141 file 1 with a special flagging mechanism. */
142 static bool flagging;
144 /* Use a tab to align output lines (-T). */
145 static bool initial_tab;
147 /* If nonzero, do not output information for overlapping diffs. */
148 static bool simple_only;
150 /* If nonzero, do not output information for non-overlapping diffs. */
151 static bool overlap_only;
153 /* If nonzero, show information for DIFF_2ND diffs. */
154 static bool show_2nd;
156 /* If nonzero, include `:wq' at the end of the script
157 to write out the file being edited. */
158 static bool finalwrite;
160 /* If nonzero, output a merged file. */
161 static bool merge;
163 char *program_name;
165 static char *read_diff (char const *, char const *, char **);
166 static char *scan_diff_line (char *, char **, size_t *, char *, char);
167 static enum diff_type process_diff_control (char **, struct diff_block *);
168 static bool compare_line_list (char * const[], size_t const[], char * const[], size_t const[], lin);
169 static bool copy_stringlist (char * const[], size_t const[], char *[], size_t[], lin);
170 static bool output_diff3_edscript (FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
171 static bool output_diff3_merge (FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
172 static struct diff3_block *create_diff3_block (lin, lin, lin, lin, lin, lin);
173 static struct diff3_block *make_3way_diff (struct diff_block *, struct diff_block *);
174 static struct diff3_block *reverse_diff3_blocklist (struct diff3_block *);
175 static struct diff3_block *using_to_diff3_block (struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *);
176 static struct diff_block *process_diff (char const *, char const *, struct diff_block **);
177 static void check_stdout (void);
178 static void fatal (char const *) __attribute__((noreturn));
179 static void output_diff3 (FILE *, struct diff3_block *, int const[3], int const[3]);
180 static void perror_with_exit (char const *) __attribute__((noreturn));
181 static void try_help (char const *, char const *) __attribute__((noreturn));
182 static void usage (void);
184 static char const *diff_program = DEFAULT_DIFF_PROGRAM;
186 /* Values for long options that do not have single-letter equivalents. */
187 enum
189 DIFF_PROGRAM_OPTION = CHAR_MAX + 1,
190 HELP_OPTION,
191 STRIP_TRAILING_CR_OPTION
194 static struct option const longopts[] =
196 {"diff-program", 1, 0, DIFF_PROGRAM_OPTION},
197 {"easy-only", 0, 0, '3'},
198 {"ed", 0, 0, 'e'},
199 {"help", 0, 0, HELP_OPTION},
200 {"initial-tab", 0, 0, 'T'},
201 {"label", 1, 0, 'L'},
202 {"merge", 0, 0, 'm'},
203 {"overlap-only", 0, 0, 'x'},
204 {"show-all", 0, 0, 'A'},
205 {"show-overlap", 0, 0, 'E'},
206 {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},
207 {"text", 0, 0, 'a'},
208 {"version", 0, 0, 'v'},
209 {0, 0, 0, 0}
213 main (int argc, char **argv)
215 int c, i;
216 int common;
217 int mapping[3];
218 int rev_mapping[3];
219 int incompat = 0;
220 bool conflicts_found;
221 struct diff_block *thread0, *thread1, *last_block;
222 struct diff3_block *diff3;
223 int tag_count = 0;
224 char *tag_strings[3];
225 char *commonname;
226 char **file;
227 struct stat statb;
229 exit_failure = 2;
230 initialize_main (&argc, &argv);
231 program_name = argv[0];
232 setlocale (LC_ALL, "");
233 bindtextdomain (PACKAGE, LOCALEDIR);
234 textdomain (PACKAGE);
235 c_stack_action (0);
237 while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != -1)
239 switch (c)
241 case 'a':
242 text = true;
243 break;
244 case 'A':
245 show_2nd = true;
246 flagging = true;
247 incompat++;
248 break;
249 case 'x':
250 overlap_only = true;
251 incompat++;
252 break;
253 case '3':
254 simple_only = true;
255 incompat++;
256 break;
257 case 'i':
258 finalwrite = true;
259 break;
260 case 'm':
261 merge = true;
262 break;
263 case 'X':
264 overlap_only = true;
265 /* Fall through. */
266 case 'E':
267 flagging = true;
268 /* Fall through. */
269 case 'e':
270 incompat++;
271 break;
272 case 'T':
273 initial_tab = true;
274 break;
275 case STRIP_TRAILING_CR_OPTION:
276 strip_trailing_cr = true;
277 break;
278 case 'v':
279 version_etc (stdout, "diff3", PACKAGE_NAME, PACKAGE_VERSION,
280 "Randy Smith", (char *) 0);
281 check_stdout ();
282 return EXIT_SUCCESS;
283 case DIFF_PROGRAM_OPTION:
284 diff_program = optarg;
285 break;
286 case HELP_OPTION:
287 usage ();
288 check_stdout ();
289 return EXIT_SUCCESS;
290 case 'L':
291 /* Handle up to three -L options. */
292 if (tag_count < 3)
294 tag_strings[tag_count++] = optarg;
295 break;
297 try_help ("too many file label options", 0);
298 default:
299 try_help (0, 0);
303 edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */
304 show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */
305 flagging |= ~incompat & merge;
307 if (incompat > 1 /* Ensure at most one of -AeExX3. */
308 || finalwrite & merge /* -i -m would rewrite input file. */
309 || (tag_count && ! flagging)) /* -L requires one of -AEX. */
310 try_help ("incompatible options", 0);
312 if (argc - optind != 3)
314 if (argc - optind < 3)
315 try_help ("missing operand after `%s'", argv[argc - 1]);
316 else
317 try_help ("extra operand `%s'", argv[optind + 3]);
320 file = &argv[optind];
322 for (i = tag_count; i < 3; i++)
323 tag_strings[i] = file[i];
325 /* Always compare file1 to file2, even if file2 is "-".
326 This is needed for -mAeExX3. Using the file0 as
327 the common file would produce wrong results, because if the
328 file0-file1 diffs didn't line up with the file0-file2 diffs
329 (which is entirely possible since we don't use diff's -n option),
330 diff3 might report phantom changes from file1 to file2.
332 Also, try to compare file0 to file1, because this is where
333 changes are expected to come from. Diffing between these pairs
334 of files is more likely to avoid phantom changes from file0 to file1.
336 Historically, the default common file was file2, so some older
337 applications (e.g. Emacs ediff) used file2 as the ancestor. So,
338 for compatibility, if this is a 3-way diff (not a merge or
339 edscript), prefer file2 as the common file. */
341 common = 2 - (edscript | merge);
343 if (strcmp (file[common], "-") == 0)
345 /* Sigh. We've got standard input as the common file. We can't
346 call diff twice on stdin. Use the other arg as the common
347 file instead. */
348 common = 3 - common;
349 if (strcmp (file[0], "-") == 0 || strcmp (file[common], "-") == 0)
350 fatal ("`-' specified for more than one input file");
353 mapping[0] = 0;
354 mapping[1] = 3 - common;
355 mapping[2] = common;
357 for (i = 0; i < 3; i++)
358 rev_mapping[mapping[i]] = i;
360 for (i = 0; i < 3; i++)
361 if (strcmp (file[i], "-") != 0)
363 if (stat (file[i], &statb) < 0)
364 perror_with_exit (file[i]);
365 else if (S_ISDIR (statb.st_mode))
366 error (EXIT_TROUBLE, EISDIR, "%s", file[i]);
369 #ifdef SIGCHLD
370 /* System V fork+wait does not work if SIGCHLD is ignored. */
371 signal (SIGCHLD, SIG_DFL);
372 #endif
374 /* Invoke diff twice on two pairs of input files, combine the two
375 diffs, and output them. */
377 commonname = file[rev_mapping[FILEC]];
378 thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
379 thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block);
380 diff3 = make_3way_diff (thread0, thread1);
381 if (edscript)
382 conflicts_found
383 = output_diff3_edscript (stdout, diff3, mapping, rev_mapping,
384 tag_strings[0], tag_strings[1], tag_strings[2]);
385 else if (merge)
387 if (! freopen (file[rev_mapping[FILE0]], "r", stdin))
388 perror_with_exit (file[rev_mapping[FILE0]]);
389 conflicts_found
390 = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping,
391 tag_strings[0], tag_strings[1], tag_strings[2]);
392 if (ferror (stdin))
393 fatal ("read failed");
395 else
397 output_diff3 (stdout, diff3, mapping, rev_mapping);
398 conflicts_found = false;
401 check_stdout ();
402 exit (conflicts_found);
403 return conflicts_found;
406 static void
407 try_help (char const *reason_msgid, char const *operand)
409 if (reason_msgid)
410 error (0, 0, _(reason_msgid), operand);
411 error (EXIT_TROUBLE, 0,
412 _("Try `%s --help' for more information."), program_name);
413 abort ();
416 static void
417 check_stdout (void)
419 if (ferror (stdout))
420 fatal ("write failed");
421 else if (fclose (stdout) != 0)
422 perror_with_exit (_("standard output"));
425 static char const * const option_help_msgid[] = {
426 N_("-e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE."),
427 N_("-E --show-overlap Output unmerged changes, bracketing conflicts."),
428 N_("-A --show-all Output all changes, bracketing conflicts."),
429 N_("-x --overlap-only Output overlapping changes."),
430 N_("-X Output overlapping changes, bracketing them."),
431 N_("-3 --easy-only Output unmerged nonoverlapping changes."),
433 N_("-m --merge Output merged file instead of ed script (default -A)."),
434 N_("-L LABEL --label=LABEL Use LABEL instead of file name."),
435 N_("-i Append `w' and `q' commands to ed scripts."),
436 N_("-a --text Treat all files as text."),
437 N_("--strip-trailing-cr Strip trailing carriage return on input."),
438 N_("-T --initial-tab Make tabs line up by prepending a tab."),
439 N_("--diff-program=PROGRAM Use PROGRAM to compare files."),
441 N_("-v --version Output version info."),
442 N_("--help Output this help."),
446 static void
447 usage (void)
449 char const * const *p;
451 printf (_("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n"),
452 program_name);
453 printf ("%s\n\n", _("Compare three files line by line."));
454 for (p = option_help_msgid; *p; p++)
455 if (**p)
456 printf (" %s\n", _(*p));
457 else
458 putchar ('\n');
459 printf ("\n%s\n%s\n\n%s\n",
460 _("If a FILE is `-', read standard input."),
461 _("Exit status is 0 if successful, 1 if conflicts, 2 if trouble."),
462 _("Report bugs to <bug-gnu-utils@gnu.org>."));
465 /* Combine the two diffs together into one.
466 Here is the algorithm:
468 File2 is shared in common between the two diffs.
469 Diff02 is the diff between 0 and 2.
470 Diff12 is the diff between 1 and 2.
472 1) Find the range for the first block in File2.
473 a) Take the lowest of the two ranges (in File2) in the two
474 current blocks (one from each diff) as being the low
475 water mark. Assign the upper end of this block as
476 being the high water mark and move the current block up
477 one. Mark the block just moved over as to be used.
478 b) Check the next block in the diff that the high water
479 mark is *not* from.
481 *If* the high water mark is above
482 the low end of the range in that block,
484 mark that block as to be used and move the current
485 block up. Set the high water mark to the max of
486 the high end of this block and the current. Repeat b.
488 2) Find the corresponding ranges in File0 (from the blocks
489 in diff02; line per line outside of diffs) and in File1.
490 Create a diff3_block, reserving space as indicated by the ranges.
492 3) Copy all of the pointers for file2 in. At least for now,
493 do memcmp's between corresponding strings in the two diffs.
495 4) Copy all of the pointers for file0 and 1 in. Get what is
496 needed from file2 (when there isn't a diff block, it's
497 identical to file2 within the range between diff blocks).
499 5) If the diff blocks used came from only one of the two
500 strings of diffs, then that file (i.e. the one other than
501 the common file in that diff) is the odd person out. If
502 diff blocks are used from both sets, check to see if files
503 0 and 1 match:
505 Same number of lines? If so, do a set of memcmp's (if
506 a memcmp matches; copy the pointer over; it'll be easier
507 later during comparisons). If they match, 0 & 1 are the
508 same. If not, all three different.
510 Then do it again, until the blocks are exhausted. */
513 /* Make a three way diff (chain of diff3_block's) from two two way
514 diffs (chains of diff_block's). Assume that each of the two diffs
515 passed are onto the same file (i.e. that each of the diffs were
516 made "to" the same file). Return a three way diff pointer with
517 numbering FILE0 = the other file in diff02, FILE1 = the other file
518 in diff12, and FILEC = the common file. */
520 static struct diff3_block *
521 make_3way_diff (struct diff_block *thread0, struct diff_block *thread1)
523 /* Work on the two diffs passed to it as threads. Thread number 0
524 is diff02, thread number 1 is diff12. USING is the base of the
525 list of blocks to be used to construct each block of the three
526 way diff; if no blocks from a particular thread are to be used,
527 that element of USING is 0. LAST_USING contains the last
528 elements on each of the using lists.
530 HIGH_WATER_MARK is the highest line number in the common file
531 described in any of the diffs in either of the USING lists.
532 HIGH_WATER_THREAD names the thread. Similarly BASE_WATER_MARK
533 and BASE_WATER_THREAD describe the lowest line number in the
534 common file described in any of the diffs in either of the USING
535 lists. HIGH_WATER_DIFF is the diff from which the
536 HIGH_WATER_MARK was taken.
538 HIGH_WATER_DIFF should always be equal to
539 LAST_USING[HIGH_WATER_THREAD]. OTHER_DIFF is the next diff to
540 check for higher water, and should always be equal to
541 CURRENT[HIGH_WATER_THREAD ^ 1]. OTHER_THREAD is the thread in
542 which the OTHER_DIFF is, and hence should always be equal to
543 HIGH_WATER_THREAD ^ 1.
545 LAST_DIFF is the last diff block produced by this routine, for
546 line correspondence purposes between that diff and the one
547 currently being worked on. It is ZERO_DIFF before any blocks
548 have been created. */
550 struct diff_block *using[2];
551 struct diff_block *last_using[2];
552 struct diff_block *current[2];
554 lin high_water_mark;
556 int high_water_thread;
557 int base_water_thread;
558 int other_thread;
560 struct diff_block *high_water_diff;
561 struct diff_block *other_diff;
563 struct diff3_block *result;
564 struct diff3_block *tmpblock;
565 struct diff3_block **result_end;
567 struct diff3_block const *last_diff3;
569 static struct diff3_block const zero_diff3;
571 /* Initialization */
572 result = 0;
573 result_end = &result;
574 current[0] = thread0; current[1] = thread1;
575 last_diff3 = &zero_diff3;
577 /* Sniff up the threads until we reach the end */
579 while (current[0] || current[1])
581 using[0] = using[1] = last_using[0] = last_using[1] = 0;
583 /* Setup low and high water threads, diffs, and marks. */
584 if (!current[0])
585 base_water_thread = 1;
586 else if (!current[1])
587 base_water_thread = 0;
588 else
589 base_water_thread =
590 (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
592 high_water_thread = base_water_thread;
594 high_water_diff = current[high_water_thread];
596 high_water_mark = D_HIGHLINE (high_water_diff, FC);
598 /* Make the diff you just got info from into the using class */
599 using[high_water_thread]
600 = last_using[high_water_thread]
601 = high_water_diff;
602 current[high_water_thread] = high_water_diff->next;
603 last_using[high_water_thread]->next = 0;
605 /* And mark the other diff */
606 other_thread = high_water_thread ^ 0x1;
607 other_diff = current[other_thread];
609 /* Shuffle up the ladder, checking the other diff to see if it
610 needs to be incorporated. */
611 while (other_diff
612 && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
615 /* Incorporate this diff into the using list. Note that
616 this doesn't take it off the current list */
617 if (using[other_thread])
618 last_using[other_thread]->next = other_diff;
619 else
620 using[other_thread] = other_diff;
621 last_using[other_thread] = other_diff;
623 /* Take it off the current list. Note that this following
624 code assumes that other_diff enters it equal to
625 current[high_water_thread ^ 0x1] */
626 current[other_thread] = current[other_thread]->next;
627 other_diff->next = 0;
629 /* Set the high_water stuff
630 If this comparison is equal, then this is the last pass
631 through this loop; since diff blocks within a given
632 thread cannot overlap, the high_water_mark will be
633 *below* the range_start of either of the next diffs. */
635 if (high_water_mark < D_HIGHLINE (other_diff, FC))
637 high_water_thread ^= 1;
638 high_water_diff = other_diff;
639 high_water_mark = D_HIGHLINE (other_diff, FC);
642 /* Set the other diff */
643 other_thread = high_water_thread ^ 0x1;
644 other_diff = current[other_thread];
647 /* The using lists contain a list of all of the blocks to be
648 included in this diff3_block. Create it. */
650 tmpblock = using_to_diff3_block (using, last_using,
651 base_water_thread, high_water_thread,
652 last_diff3);
654 if (!tmpblock)
655 fatal ("internal error: screwup in format of diff blocks");
657 /* Put it on the list. */
658 *result_end = tmpblock;
659 result_end = &tmpblock->next;
661 /* Set up corresponding lines correctly. */
662 last_diff3 = tmpblock;
664 return result;
667 /* Take two lists of blocks (from two separate diff threads) and put
668 them together into one diff3 block. Return a pointer to this diff3
669 block or 0 for failure.
671 All arguments besides using are for the convenience of the routine;
672 they could be derived from the using array. LAST_USING is a pair
673 of pointers to the last blocks in the using structure. LOW_THREAD
674 and HIGH_THREAD tell which threads contain the lowest and highest
675 line numbers for File0. LAST_DIFF3 contains the last diff produced
676 in the calling routine. This is used for lines mappings that
677 would still be identical to the state that diff ended in.
679 A distinction should be made in this routine between the two diffs
680 that are part of a normal two diff block, and the three diffs that
681 are part of a diff3_block. */
683 static struct diff3_block *
684 using_to_diff3_block (struct diff_block *using[2],
685 struct diff_block *last_using[2],
686 int low_thread, int high_thread,
687 struct diff3_block const *last_diff3)
689 lin low[2], high[2];
690 struct diff3_block *result;
691 struct diff_block *ptr;
692 int d;
693 lin i;
695 /* Find the range in the common file. */
696 lin lowc = D_LOWLINE (using[low_thread], FC);
697 lin highc = D_HIGHLINE (last_using[high_thread], FC);
699 /* Find the ranges in the other files.
700 If using[d] is null, that means that the file to which that diff
701 refers is equivalent to the common file over this range. */
703 for (d = 0; d < 2; d++)
704 if (using[d])
706 low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
707 high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
709 else
711 low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
712 high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
715 /* Create a block with the appropriate sizes */
716 result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
718 /* Copy information for the common file.
719 Return with a zero if any of the compares failed. */
721 for (d = 0; d < 2; d++)
722 for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
724 lin result_offset = D_LOWLINE (ptr, FC) - lowc;
726 if (!copy_stringlist (D_LINEARRAY (ptr, FC),
727 D_LENARRAY (ptr, FC),
728 D_LINEARRAY (result, FILEC) + result_offset,
729 D_LENARRAY (result, FILEC) + result_offset,
730 D_NUMLINES (ptr, FC)))
731 return 0;
734 /* Copy information for file d. First deal with anything that might be
735 before the first diff. */
737 for (d = 0; d < 2; d++)
739 struct diff_block *u = using[d];
740 lin lo = low[d], hi = high[d];
742 for (i = 0;
743 i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
744 i++)
746 D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
747 D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
750 for (ptr = u; ptr; ptr = D_NEXT (ptr))
752 lin result_offset = D_LOWLINE (ptr, FO) - lo;
753 lin linec;
755 if (!copy_stringlist (D_LINEARRAY (ptr, FO),
756 D_LENARRAY (ptr, FO),
757 D_LINEARRAY (result, FILE0 + d) + result_offset,
758 D_LENARRAY (result, FILE0 + d) + result_offset,
759 D_NUMLINES (ptr, FO)))
760 return 0;
762 /* Catch the lines between here and the next diff */
763 linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
764 for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
765 i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
766 i++)
768 D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
769 D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
770 linec++;
775 /* Set correspond */
776 if (!using[0])
777 D3_TYPE (result) = DIFF_2ND;
778 else if (!using[1])
779 D3_TYPE (result) = DIFF_1ST;
780 else
782 lin nl0 = D_NUMLINES (result, FILE0);
783 lin nl1 = D_NUMLINES (result, FILE1);
785 if (nl0 != nl1
786 || !compare_line_list (D_LINEARRAY (result, FILE0),
787 D_LENARRAY (result, FILE0),
788 D_LINEARRAY (result, FILE1),
789 D_LENARRAY (result, FILE1),
790 nl0))
791 D3_TYPE (result) = DIFF_ALL;
792 else
793 D3_TYPE (result) = DIFF_3RD;
796 return result;
799 /* Copy pointers from a list of strings to a different list of
800 strings. If a spot in the second list is already filled, make sure
801 that it is filled with the same string; if not, return false, the copy
802 incomplete. Upon successful completion of the copy, return true. */
804 static bool
805 copy_stringlist (char * const fromptrs[], size_t const fromlengths[],
806 char *toptrs[], size_t tolengths[],
807 lin copynum)
809 register char * const *f = fromptrs;
810 register char **t = toptrs;
811 register size_t const *fl = fromlengths;
812 register size_t *tl = tolengths;
814 while (copynum--)
816 if (*t)
818 if (*fl != *tl || memcmp (*f, *t, *fl) != 0)
819 return false;
821 else
823 *t = *f;
824 *tl = *fl;
827 t++; f++; tl++; fl++;
830 return true;
833 /* Create a diff3_block, with ranges as specified in the arguments.
834 Allocate the arrays for the various pointers (and zero them) based
835 on the arguments passed. Return the block as a result. */
837 static struct diff3_block *
838 create_diff3_block (lin low0, lin high0,
839 lin low1, lin high1,
840 lin low2, lin high2)
842 struct diff3_block *result = xmalloc (sizeof *result);
843 lin numlines;
845 D3_TYPE (result) = ERROR;
846 D_NEXT (result) = 0;
848 /* Assign ranges */
849 D_LOWLINE (result, FILE0) = low0;
850 D_HIGHLINE (result, FILE0) = high0;
851 D_LOWLINE (result, FILE1) = low1;
852 D_HIGHLINE (result, FILE1) = high1;
853 D_LOWLINE (result, FILE2) = low2;
854 D_HIGHLINE (result, FILE2) = high2;
856 /* Allocate and zero space */
857 numlines = D_NUMLINES (result, FILE0);
858 if (numlines)
860 D_LINEARRAY (result, FILE0) = xcalloc (numlines, sizeof (char *));
861 D_LENARRAY (result, FILE0) = xcalloc (numlines, sizeof (size_t));
863 else
865 D_LINEARRAY (result, FILE0) = 0;
866 D_LENARRAY (result, FILE0) = 0;
869 numlines = D_NUMLINES (result, FILE1);
870 if (numlines)
872 D_LINEARRAY (result, FILE1) = xcalloc (numlines, sizeof (char *));
873 D_LENARRAY (result, FILE1) = xcalloc (numlines, sizeof (size_t));
875 else
877 D_LINEARRAY (result, FILE1) = 0;
878 D_LENARRAY (result, FILE1) = 0;
881 numlines = D_NUMLINES (result, FILE2);
882 if (numlines)
884 D_LINEARRAY (result, FILE2) = xcalloc (numlines, sizeof (char *));
885 D_LENARRAY (result, FILE2) = xcalloc (numlines, sizeof (size_t));
887 else
889 D_LINEARRAY (result, FILE2) = 0;
890 D_LENARRAY (result, FILE2) = 0;
893 /* Return */
894 return result;
897 /* Compare two lists of lines of text.
898 Return 1 if they are equivalent, 0 if not. */
900 static bool
901 compare_line_list (char * const list1[], size_t const lengths1[],
902 char * const list2[], size_t const lengths2[],
903 lin nl)
905 char * const *l1 = list1;
906 char * const *l2 = list2;
907 size_t const *lgths1 = lengths1;
908 size_t const *lgths2 = lengths2;
910 while (nl--)
911 if (!*l1 || !*l2 || *lgths1 != *lgths2++
912 || memcmp (*l1++, *l2++, *lgths1++) != 0)
913 return false;
914 return true;
917 /* Input and parse two way diffs. */
919 static struct diff_block *
920 process_diff (char const *filea,
921 char const *fileb,
922 struct diff_block **last_block)
924 char *diff_contents;
925 char *diff_limit;
926 char *scan_diff;
927 enum diff_type dt;
928 lin i;
929 struct diff_block *block_list, **block_list_end, *bptr;
930 size_t too_many_lines = (PTRDIFF_MAX
931 / MIN (sizeof *bptr->lines[1],
932 sizeof *bptr->lengths[1]));
934 diff_limit = read_diff (filea, fileb, &diff_contents);
935 scan_diff = diff_contents;
936 block_list_end = &block_list;
937 bptr = 0; /* Pacify `gcc -W'. */
939 while (scan_diff < diff_limit)
941 bptr = xmalloc (sizeof *bptr);
942 bptr->lines[0] = bptr->lines[1] = 0;
943 bptr->lengths[0] = bptr->lengths[1] = 0;
945 dt = process_diff_control (&scan_diff, bptr);
946 if (dt == ERROR || *scan_diff != '\n')
948 fprintf (stderr, _("%s: diff failed: "), program_name);
951 putc (*scan_diff, stderr);
953 while (*scan_diff++ != '\n');
954 exit (EXIT_TROUBLE);
956 scan_diff++;
958 /* Force appropriate ranges to be null, if necessary */
959 switch (dt)
961 case ADD:
962 bptr->ranges[0][0]++;
963 break;
964 case DELETE:
965 bptr->ranges[1][0]++;
966 break;
967 case CHANGE:
968 break;
969 default:
970 fatal ("internal error: invalid diff type in process_diff");
971 break;
974 /* Allocate space for the pointers for the lines from filea, and
975 parcel them out among these pointers */
976 if (dt != ADD)
978 lin numlines = D_NUMLINES (bptr, 0);
979 if (too_many_lines <= numlines)
980 xalloc_die ();
981 bptr->lines[0] = xmalloc (numlines * sizeof *bptr->lines[0]);
982 bptr->lengths[0] = xmalloc (numlines * sizeof *bptr->lengths[0]);
983 for (i = 0; i < numlines; i++)
984 scan_diff = scan_diff_line (scan_diff,
985 &(bptr->lines[0][i]),
986 &(bptr->lengths[0][i]),
987 diff_limit,
988 '<');
991 /* Get past the separator for changes */
992 if (dt == CHANGE)
994 if (strncmp (scan_diff, "---\n", 4))
995 fatal ("invalid diff format; invalid change separator");
996 scan_diff += 4;
999 /* Allocate space for the pointers for the lines from fileb, and
1000 parcel them out among these pointers */
1001 if (dt != DELETE)
1003 lin numlines = D_NUMLINES (bptr, 1);
1004 if (too_many_lines <= numlines)
1005 xalloc_die ();
1006 bptr->lines[1] = xmalloc (numlines * sizeof *bptr->lines[1]);
1007 bptr->lengths[1] = xmalloc (numlines * sizeof *bptr->lengths[1]);
1008 for (i = 0; i < numlines; i++)
1009 scan_diff = scan_diff_line (scan_diff,
1010 &(bptr->lines[1][i]),
1011 &(bptr->lengths[1][i]),
1012 diff_limit,
1013 '>');
1016 /* Place this block on the blocklist. */
1017 *block_list_end = bptr;
1018 block_list_end = &bptr->next;
1021 *block_list_end = 0;
1022 *last_block = bptr;
1023 return block_list;
1026 /* Skip tabs and spaces, and return the first character after them. */
1028 static char *
1029 skipwhite (char *s)
1031 while (*s == ' ' || *s == '\t')
1032 s++;
1033 return s;
1036 /* Read a nonnegative line number from S, returning the address of the
1037 first character after the line number, and storing the number into
1038 *PNUM. Return 0 if S does not point to a valid line number. */
1040 static char *
1041 readnum (char *s, lin *pnum)
1043 unsigned char c = *s;
1044 lin num = 0;
1046 if (! ISDIGIT (c))
1047 return 0;
1051 num = c - '0' + num * 10;
1052 c = *++s;
1054 while (ISDIGIT (c));
1056 *pnum = num;
1057 return s;
1060 /* Parse a normal format diff control string. Return the type of the
1061 diff (ERROR if the format is bad). All of the other important
1062 information is filled into to the structure pointed to by db, and
1063 the string pointer (whose location is passed to this routine) is
1064 updated to point beyond the end of the string parsed. Note that
1065 only the ranges in the diff_block will be set by this routine.
1067 If some specific pair of numbers has been reduced to a single
1068 number, then both corresponding numbers in the diff block are set
1069 to that number. In general these numbers are interpreted as ranges
1070 inclusive, unless being used by the ADD or DELETE commands. It is
1071 assumed that these will be special cased in a superior routine. */
1073 static enum diff_type
1074 process_diff_control (char **string, struct diff_block *db)
1076 char *s = *string;
1077 enum diff_type type;
1079 /* Read first set of digits */
1080 s = readnum (skipwhite (s), &db->ranges[0][RANGE_START]);
1081 if (! s)
1082 return ERROR;
1084 /* Was that the only digit? */
1085 s = skipwhite (s);
1086 if (*s == ',')
1088 s = readnum (s + 1, &db->ranges[0][RANGE_END]);
1089 if (! s)
1090 return ERROR;
1092 else
1093 db->ranges[0][RANGE_END] = db->ranges[0][RANGE_START];
1095 /* Get the letter */
1096 s = skipwhite (s);
1097 switch (*s)
1099 case 'a':
1100 type = ADD;
1101 break;
1102 case 'c':
1103 type = CHANGE;
1104 break;
1105 case 'd':
1106 type = DELETE;
1107 break;
1108 default:
1109 return ERROR; /* Bad format */
1111 s++; /* Past letter */
1113 /* Read second set of digits */
1114 s = readnum (skipwhite (s), &db->ranges[1][RANGE_START]);
1115 if (! s)
1116 return ERROR;
1118 /* Was that the only digit? */
1119 s = skipwhite (s);
1120 if (*s == ',')
1122 s = readnum (s + 1, &db->ranges[1][RANGE_END]);
1123 if (! s)
1124 return ERROR;
1125 s = skipwhite (s); /* To move to end */
1127 else
1128 db->ranges[1][RANGE_END] = db->ranges[1][RANGE_START];
1130 *string = s;
1131 return type;
1134 static char *
1135 read_diff (char const *filea,
1136 char const *fileb,
1137 char **output_placement)
1139 char *diff_result;
1140 size_t current_chunk_size, total;
1141 int fd, wstatus, status;
1142 int werrno = 0;
1143 struct stat pipestat;
1145 #if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
1147 char const *argv[9];
1148 char const **ap;
1149 int fds[2];
1150 pid_t pid;
1152 ap = argv;
1153 *ap++ = diff_program;
1154 if (text)
1155 *ap++ = "-a";
1156 if (strip_trailing_cr)
1157 *ap++ = "--strip-trailing-cr";
1158 *ap++ = "--horizon-lines=100";
1159 *ap++ = "--";
1160 *ap++ = filea;
1161 *ap++ = fileb;
1162 *ap = 0;
1164 if (pipe (fds) != 0)
1165 perror_with_exit ("pipe");
1167 pid = vfork ();
1168 if (pid == 0)
1170 /* Child */
1171 close (fds[0]);
1172 if (fds[1] != STDOUT_FILENO)
1174 dup2 (fds[1], STDOUT_FILENO);
1175 close (fds[1]);
1178 /* The cast to (char **) is needed for portability to older
1179 hosts with a nonstandard prototype for execvp. */
1180 execvp (diff_program, (char **) argv);
1182 _exit (errno == ENOENT ? 127 : 126);
1185 if (pid == -1)
1186 perror_with_exit ("fork");
1188 close (fds[1]); /* Prevent erroneous lack of EOF */
1189 fd = fds[0];
1191 #else
1193 FILE *fpipe;
1194 char const args[] = " --horizon-lines=100 -- ";
1195 char *command = xmalloc (quote_system_arg (0, diff_program)
1196 + sizeof "-a"
1197 + sizeof "--strip-trailing-cr"
1198 + sizeof args - 1
1199 + quote_system_arg (0, filea) + 1
1200 + quote_system_arg (0, fileb) + 1);
1201 char *p = command;
1202 p += quote_system_arg (p, diff_program);
1203 if (text)
1205 strcpy (p, " -a");
1206 p += 3;
1208 if (strip_trailing_cr)
1210 strcpy (p, " --strip-trailing-cr");
1211 p += 20;
1213 strcpy (p, args);
1214 p += sizeof args - 1;
1215 p += quote_system_arg (p, filea);
1216 *p++ = ' ';
1217 p += quote_system_arg (p, fileb);
1218 *p = 0;
1219 errno = 0;
1220 fpipe = popen (command, "r");
1221 if (!fpipe)
1222 perror_with_exit (command);
1223 free (command);
1224 fd = fileno (fpipe);
1226 #endif
1228 if (fstat (fd, &pipestat) != 0)
1229 perror_with_exit ("fstat");
1230 current_chunk_size = MAX (1, STAT_BLOCKSIZE (pipestat));
1231 diff_result = xmalloc (current_chunk_size);
1232 total = 0;
1234 for (;;)
1236 size_t bytes_to_read = current_chunk_size - total;
1237 size_t bytes = block_read (fd, diff_result + total, bytes_to_read);
1238 total += bytes;
1239 if (bytes != bytes_to_read)
1241 if (bytes == SIZE_MAX)
1242 perror_with_exit (_("read failed"));
1243 break;
1245 if (PTRDIFF_MAX / 2 <= current_chunk_size)
1246 xalloc_die ();
1247 current_chunk_size *= 2;
1248 diff_result = xrealloc (diff_result, current_chunk_size);
1251 if (total != 0 && diff_result[total-1] != '\n')
1252 fatal ("invalid diff format; incomplete last line");
1254 *output_placement = diff_result;
1256 #if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
1258 wstatus = pclose (fpipe);
1259 if (wstatus == -1)
1260 werrno = errno;
1262 #else
1264 if (close (fd) != 0)
1265 perror_with_exit ("close");
1266 if (waitpid (pid, &wstatus, 0) < 0)
1267 perror_with_exit ("waitpid");
1269 #endif
1271 status = ! werrno && WIFEXITED (wstatus) ? WEXITSTATUS (wstatus) : INT_MAX;
1273 if (EXIT_TROUBLE <= status)
1274 error (EXIT_TROUBLE, werrno,
1275 _(status == 126
1276 ? "subsidiary program `%s' could not be invoked"
1277 : status == 127
1278 ? "subsidiary program `%s' not found"
1279 : status == INT_MAX
1280 ? "subsidiary program `%s' failed"
1281 : "subsidiary program `%s' failed (exit status %d)"),
1282 diff_program, status);
1284 return diff_result + total;
1288 /* Scan a regular diff line (consisting of > or <, followed by a
1289 space, followed by text (including nulls) up to a newline.
1291 This next routine began life as a macro and many parameters in it
1292 are used as call-by-reference values. */
1293 static char *
1294 scan_diff_line (char *scan_ptr, char **set_start, size_t *set_length,
1295 char *limit, char leadingchar)
1297 char *line_ptr;
1299 if (!(scan_ptr[0] == leadingchar
1300 && scan_ptr[1] == ' '))
1301 fatal ("invalid diff format; incorrect leading line chars");
1303 *set_start = line_ptr = scan_ptr + 2;
1304 while (*line_ptr++ != '\n')
1305 continue;
1307 /* Include newline if the original line ended in a newline,
1308 or if an edit script is being generated.
1309 Copy any missing newline message to stderr if an edit script is being
1310 generated, because edit scripts cannot handle missing newlines.
1311 Return the beginning of the next line. */
1312 *set_length = line_ptr - *set_start;
1313 if (line_ptr < limit && *line_ptr == '\\')
1315 if (edscript)
1316 fprintf (stderr, "%s:", program_name);
1317 else
1318 --*set_length;
1319 line_ptr++;
1322 if (edscript)
1323 putc (*line_ptr, stderr);
1325 while (*line_ptr++ != '\n');
1328 return line_ptr;
1331 /* Output a three way diff passed as a list of diff3_block's. The
1332 argument MAPPING is indexed by external file number (in the
1333 argument list) and contains the internal file number (from the diff
1334 passed). This is important because the user expects outputs in
1335 terms of the argument list number, and the diff passed may have
1336 been done slightly differently (if the last argument was "-", for
1337 example). REV_MAPPING is the inverse of MAPPING. */
1339 static void
1340 output_diff3 (FILE *outputfile, struct diff3_block *diff,
1341 int const mapping[3], int const rev_mapping[3])
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" : " ";
1353 for (ptr = diff; ptr; ptr = D_NEXT (ptr))
1355 char x[2];
1357 switch (ptr->correspond)
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];
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");
1376 fprintf (outputfile, "====%s\n", x);
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))
1382 int realfile = mapping[i];
1383 lin lowt = D_LOWLINE (ptr, realfile);
1384 lin hight = D_HIGHLINE (ptr, realfile);
1385 long int llowt = lowt;
1386 long int lhight = hight;
1388 fprintf (outputfile, "%d:", i + 1);
1389 switch (lowt - hight)
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;
1402 if (i == dontprint) continue;
1404 if (lowt <= hight)
1406 line = 0;
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);
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"));
1424 /* Output to OUTPUTFILE the lines of B taken from FILENUM. Double any
1425 initial '.'s; yield nonzero if any initial '.'s were doubled. */
1427 static bool
1428 dotlines (FILE *outputfile, struct diff3_block *b, int filenum)
1430 lin i;
1431 bool leading_dot = false;
1433 for (i = 0;
1434 i < D_NUMLINES (b, filenum);
1435 i++)
1437 char *line = D_RELNUM (b, filenum, i);
1438 if (line[0] == '.')
1440 leading_dot = true;
1441 fprintf (outputfile, ".");
1443 fwrite (line, sizeof (char),
1444 D_RELLEN (b, filenum, i), outputfile);
1447 return leading_dot;
1450 /* Output to OUTPUTFILE a '.' line. If LEADING_DOT is true, also
1451 output a command that removes initial '.'s starting with line START
1452 and continuing for NUM lines. (START is long int, not lin, for
1453 convenience with printf %ld formats.) */
1455 static void
1456 undotlines (FILE *outputfile, bool leading_dot, long int start, lin num)
1458 fprintf (outputfile, ".\n");
1459 if (leading_dot)
1461 if (num == 1)
1462 fprintf (outputfile, "%lds/^\\.//\n", start);
1463 else
1464 fprintf (outputfile, "%ld,%lds/^\\.//\n", start, start + num - 1);
1468 /* Output a diff3 set of blocks as an ed script. This script applies
1469 the changes between file's 2 & 3 to file 1. Take the precise
1470 format of the ed script to be output from global variables set
1471 during options processing. Reverse the order of
1472 the set of diff3 blocks in DIFF; this gets
1473 around the problems involved with changing line numbers in an ed
1474 script.
1476 As in `output_diff3', the variable MAPPING maps from file number
1477 according to the argument list to file number according to the diff
1478 passed. All files listed below are in terms of the argument list.
1479 REV_MAPPING is the inverse of MAPPING.
1481 FILE0, FILE1 and FILE2 are the strings to print as the names of the
1482 three files. These may be the actual names, or may be the
1483 arguments specified with -L.
1485 Return 1 if conflicts were found. */
1487 static bool
1488 output_diff3_edscript (FILE *outputfile, struct diff3_block *diff,
1489 int const mapping[3], int const rev_mapping[3],
1490 char const *file0, char const *file1, char const *file2)
1492 bool leading_dot;
1493 bool conflicts_found = false;
1494 bool conflict;
1495 struct diff3_block *b;
1497 for (b = reverse_diff3_blocklist (diff); b; b = b->next)
1499 /* Must do mapping correctly. */
1500 enum diff_type type
1501 = (b->correspond == DIFF_ALL
1502 ? DIFF_ALL
1503 : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
1505 long int low0, high0;
1507 /* If we aren't supposed to do this output block, skip it. */
1508 switch (type)
1510 default: continue;
1511 case DIFF_2ND: if (!show_2nd) continue; conflict = true; break;
1512 case DIFF_3RD: if (overlap_only) continue; conflict = false; break;
1513 case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
1516 low0 = D_LOWLINE (b, mapping[FILE0]);
1517 high0 = D_HIGHLINE (b, mapping[FILE0]);
1519 if (conflict)
1521 conflicts_found = true;
1524 /* Mark end of conflict. */
1526 fprintf (outputfile, "%lda\n", high0);
1527 leading_dot = false;
1528 if (type == DIFF_ALL)
1530 if (show_2nd)
1532 /* Append lines from FILE1. */
1533 fprintf (outputfile, "||||||| %s\n", file1);
1534 leading_dot = dotlines (outputfile, b, mapping[FILE1]);
1536 /* Append lines from FILE2. */
1537 fprintf (outputfile, "=======\n");
1538 leading_dot |= dotlines (outputfile, b, mapping[FILE2]);
1540 fprintf (outputfile, ">>>>>>> %s\n", file2);
1541 undotlines (outputfile, leading_dot, high0 + 2,
1542 (D_NUMLINES (b, mapping[FILE1])
1543 + D_NUMLINES (b, mapping[FILE2]) + 1));
1546 /* Mark start of conflict. */
1548 fprintf (outputfile, "%lda\n<<<<<<< %s\n", low0 - 1,
1549 type == DIFF_ALL ? file0 : file1);
1550 leading_dot = false;
1551 if (type == DIFF_2ND)
1553 /* Prepend lines from FILE1. */
1554 leading_dot = dotlines (outputfile, b, mapping[FILE1]);
1555 fprintf (outputfile, "=======\n");
1557 undotlines (outputfile, leading_dot, low0 + 1,
1558 D_NUMLINES (b, mapping[FILE1]));
1560 else if (D_NUMLINES (b, mapping[FILE2]) == 0)
1561 /* Write out a delete */
1563 if (low0 == high0)
1564 fprintf (outputfile, "%ldd\n", low0);
1565 else
1566 fprintf (outputfile, "%ld,%ldd\n", low0, high0);
1568 else
1569 /* Write out an add or change */
1571 switch (high0 - low0)
1573 case -1:
1574 fprintf (outputfile, "%lda\n", high0);
1575 break;
1576 case 0:
1577 fprintf (outputfile, "%ldc\n", high0);
1578 break;
1579 default:
1580 fprintf (outputfile, "%ld,%ldc\n", low0, high0);
1581 break;
1584 undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]),
1585 low0, D_NUMLINES (b, mapping[FILE2]));
1588 if (finalwrite) fprintf (outputfile, "w\nq\n");
1589 return conflicts_found;
1592 /* Read from INFILE and output to OUTPUTFILE a set of diff3_blocks
1593 DIFF as a merged file. This acts like 'ed file0
1594 <[output_diff3_edscript]', except that it works even for binary
1595 data or incomplete lines.
1597 As before, MAPPING maps from arg list file number to diff file
1598 number, REV_MAPPING is its inverse, and FILE0, FILE1, and FILE2 are
1599 the names of the files.
1601 Return 1 if conflicts were found. */
1603 static bool
1604 output_diff3_merge (FILE *infile, FILE *outputfile, struct diff3_block *diff,
1605 int const mapping[3], int const rev_mapping[3],
1606 char const *file0, char const *file1, char const *file2)
1608 int c;
1609 lin i;
1610 bool conflicts_found = false;
1611 bool conflict;
1612 struct diff3_block *b;
1613 lin linesread = 0;
1615 for (b = diff; b; b = b->next)
1617 /* Must do mapping correctly. */
1618 enum diff_type type
1619 = ((b->correspond == DIFF_ALL)
1620 ? DIFF_ALL
1621 : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
1622 char const *format_2nd = "<<<<<<< %s\n";
1624 /* If we aren't supposed to do this output block, skip it. */
1625 switch (type)
1627 default: continue;
1628 case DIFF_2ND: if (!show_2nd) continue; conflict = true; break;
1629 case DIFF_3RD: if (overlap_only) continue; conflict = false; break;
1630 case DIFF_ALL: if (simple_only) continue; conflict = flagging;
1631 format_2nd = "||||||| %s\n";
1632 break;
1635 /* Copy I lines from file 0. */
1636 i = D_LOWLINE (b, FILE0) - linesread - 1;
1637 linesread += i;
1638 while (0 <= --i)
1641 c = getc (infile);
1642 if (c == EOF)
1644 if (ferror (infile))
1645 perror_with_exit (_("read failed"));
1646 else if (feof (infile))
1647 fatal ("input file shrank");
1649 putc (c, outputfile);
1651 while (c != '\n');
1653 if (conflict)
1655 conflicts_found = true;
1657 if (type == DIFF_ALL)
1659 /* Put in lines from FILE0 with bracket. */
1660 fprintf (outputfile, "<<<<<<< %s\n", file0);
1661 for (i = 0;
1662 i < D_NUMLINES (b, mapping[FILE0]);
1663 i++)
1664 fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
1665 D_RELLEN (b, mapping[FILE0], i), outputfile);
1668 if (show_2nd)
1670 /* Put in lines from FILE1 with bracket. */
1671 fprintf (outputfile, format_2nd, file1);
1672 for (i = 0;
1673 i < D_NUMLINES (b, mapping[FILE1]);
1674 i++)
1675 fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char),
1676 D_RELLEN (b, mapping[FILE1], i), outputfile);
1679 fprintf (outputfile, "=======\n");
1682 /* Put in lines from FILE2. */
1683 for (i = 0;
1684 i < D_NUMLINES (b, mapping[FILE2]);
1685 i++)
1686 fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
1687 D_RELLEN (b, mapping[FILE2], i), outputfile);
1689 if (conflict)
1690 fprintf (outputfile, ">>>>>>> %s\n", file2);
1692 /* Skip I lines in file 0. */
1693 i = D_NUMLINES (b, FILE0);
1694 linesread += i;
1695 while (0 <= --i)
1696 while ((c = getc (infile)) != '\n')
1697 if (c == EOF)
1699 if (ferror (infile))
1700 perror_with_exit (_("read failed"));
1701 else if (feof (infile))
1703 if (i || b->next)
1704 fatal ("input file shrank");
1705 return conflicts_found;
1709 /* Copy rest of common file. */
1710 while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
1711 putc (c, outputfile);
1712 return conflicts_found;
1715 /* Reverse the order of the list of diff3 blocks. */
1717 static struct diff3_block *
1718 reverse_diff3_blocklist (struct diff3_block *diff)
1720 register struct diff3_block *tmp, *next, *prev;
1722 for (tmp = diff, prev = 0; tmp; tmp = next)
1724 next = tmp->next;
1725 tmp->next = prev;
1726 prev = tmp;
1729 return prev;
1732 static void
1733 fatal (char const *msgid)
1735 error (EXIT_TROUBLE, 0, "%s", _(msgid));
1736 abort ();
1739 static void
1740 perror_with_exit (char const *string)
1742 error (EXIT_TROUBLE, errno, "%s", string);
1743 abort ();