1 /* diff3 - compare three files line by line
3 Copyright (C) 1988-1989, 1992-1996, 1998, 2001-2002, 2004, 2006, 2009-2010
4 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 3 of the License, or
9 (at your option) 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. See the
14 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. If not, see <http://www.gnu.org/licenses/>. */
23 #include <unlocked-io.h>
29 #include <file-type.h>
34 #include <version-etc.h>
38 /* The official name of this program (e.g., no `g' prefix). */
39 #define PROGRAM_NAME "diff3"
42 proper_name ("Randy Smith")
44 /* Internal data structures and macros for the diff3 program; includes
45 data structures for both diff3 diffs and normal diffs. */
47 /* Different files within a three way diff. */
52 /* A three way diff is built from two two-way diffs; the file which
53 the two two-way diffs share is: */
56 /* Different files within a two way diff.
57 FC is the common file, FO the other file. */
61 /* The ranges are indexed by */
66 ERROR, /* Should not be used */
67 ADD, /* Two way diff add */
68 CHANGE, /* Two way diff change */
69 DELETE, /* Two way diff delete */
70 DIFF_ALL, /* All three are different */
71 DIFF_1ST, /* Only the first is different */
72 DIFF_2ND, /* Only the second */
73 DIFF_3RD /* Only the third */
78 lin ranges[2][2]; /* Ranges are inclusive */
79 char **lines[2]; /* The actual lines (may contain nulls) */
80 size_t *lengths[2]; /* Line lengths (including newlines, if any) */
81 struct diff_block *next;
87 enum diff_type correspond; /* Type of diff */
88 lin ranges[3][2]; /* Ranges are inclusive */
89 char **lines[3]; /* The actual lines (may contain nulls) */
90 size_t *lengths[3]; /* Line lengths (including newlines, if any) */
91 struct diff3_block *next;
94 /* Access the ranges on a diff block. */
95 #define D_LOWLINE(diff, filenum) \
96 ((diff)->ranges[filenum][RANGE_START])
97 #define D_HIGHLINE(diff, filenum) \
98 ((diff)->ranges[filenum][RANGE_END])
99 #define D_NUMLINES(diff, filenum) \
100 (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
102 /* Access the line numbers in a file in a diff by relative line
103 numbers (i.e. line number within the diff itself). Note that these
104 are lvalues and can be used for assignment. */
105 #define D_RELNUM(diff, filenum, linenum) \
106 ((diff)->lines[filenum][linenum])
107 #define D_RELLEN(diff, filenum, linenum) \
108 ((diff)->lengths[filenum][linenum])
110 /* And get at them directly, when that should be necessary. */
111 #define D_LINEARRAY(diff, filenum) \
112 ((diff)->lines[filenum])
113 #define D_LENARRAY(diff, filenum) \
114 ((diff)->lengths[filenum])
117 #define D_NEXT(diff) ((diff)->next)
119 /* Access the type of a diff3 block. */
120 #define D3_TYPE(diff) ((diff)->correspond)
122 /* Line mappings based on diffs. The first maps off the top of the
123 diff, the second off of the bottom. */
124 #define D_HIGH_MAPLINE(diff, fromfile, tofile, linenum) \
126 - D_HIGHLINE ((diff), (fromfile)) \
127 + D_HIGHLINE ((diff), (tofile)))
129 #define D_LOW_MAPLINE(diff, fromfile, tofile, linenum) \
131 - D_LOWLINE ((diff), (fromfile)) \
132 + D_LOWLINE ((diff), (tofile)))
134 /* Options variables for flags set on command line. */
136 /* If nonzero, treat all files as text files, never as binary. */
139 /* Remove trailing carriage returns from input. */
140 static bool strip_trailing_cr;
142 /* If nonzero, write out an ed script instead of the standard diff3 format. */
143 static bool edscript;
145 /* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
146 preserve the lines which would normally be deleted from
147 file 1 with a special flagging mechanism. */
148 static bool flagging;
150 /* Use a tab to align output lines (-T). */
151 static bool initial_tab;
153 /* If nonzero, do not output information for overlapping diffs. */
154 static bool simple_only;
156 /* If nonzero, do not output information for non-overlapping diffs. */
157 static bool overlap_only;
159 /* If nonzero, show information for DIFF_2ND diffs. */
160 static bool show_2nd;
162 /* If nonzero, include `:wq' at the end of the script
163 to write out the file being edited. */
164 static bool finalwrite;
166 /* If nonzero, output a merged file. */
169 static char *read_diff (char const *, char const *, char **);
170 static char *scan_diff_line (char *, char **, size_t *, char *, char);
171 static enum diff_type process_diff_control (char **, struct diff_block *);
172 static bool compare_line_list (char * const[], size_t const[], char * const[], size_t const[], lin);
173 static bool copy_stringlist (char * const[], size_t const[], char *[], size_t[], lin);
174 static bool output_diff3_edscript (FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
175 static bool output_diff3_merge (FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
176 static struct diff3_block *create_diff3_block (lin, lin, lin, lin, lin, lin);
177 static struct diff3_block *make_3way_diff (struct diff_block *, struct diff_block *);
178 static struct diff3_block *reverse_diff3_blocklist (struct diff3_block *);
179 static struct diff3_block *using_to_diff3_block (struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *);
180 static struct diff_block *process_diff (char const *, char const *, struct diff_block **);
181 static void check_stdout (void);
182 static void fatal (char const *) __attribute__((noreturn));
183 static void output_diff3 (FILE *, struct diff3_block *, int const[3], int const[3]);
184 static void perror_with_exit (char const *) __attribute__((noreturn));
185 static void try_help (char const *, char const *) __attribute__((noreturn));
186 static void usage (void);
188 static char const *diff_program = DEFAULT_DIFF_PROGRAM;
190 /* Values for long options that do not have single-letter equivalents. */
193 DIFF_PROGRAM_OPTION = CHAR_MAX + 1,
195 STRIP_TRAILING_CR_OPTION
198 static struct option const longopts[] =
200 {"diff-program", 1, 0, DIFF_PROGRAM_OPTION},
201 {"easy-only", 0, 0, '3'},
203 {"help", 0, 0, HELP_OPTION},
204 {"initial-tab", 0, 0, 'T'},
205 {"label", 1, 0, 'L'},
206 {"merge", 0, 0, 'm'},
207 {"overlap-only", 0, 0, 'x'},
208 {"show-all", 0, 0, 'A'},
209 {"show-overlap", 0, 0, 'E'},
210 {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},
212 {"version", 0, 0, 'v'},
217 main (int argc, char **argv)
224 bool conflicts_found;
225 struct diff_block *thread0, *thread1, *last_block;
226 struct diff3_block *diff3;
228 char *tag_strings[3];
233 exit_failure = EXIT_TROUBLE;
234 initialize_main (&argc, &argv);
235 set_program_name (argv[0]);
236 setlocale (LC_ALL, "");
237 bindtextdomain (PACKAGE, LOCALEDIR);
238 textdomain (PACKAGE);
241 while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != -1)
279 case STRIP_TRAILING_CR_OPTION:
280 strip_trailing_cr = true;
283 version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, PACKAGE_VERSION,
284 AUTHORS, (char *) NULL);
287 case DIFF_PROGRAM_OPTION:
288 diff_program = optarg;
295 /* Handle up to three -L options. */
298 tag_strings[tag_count++] = optarg;
301 try_help ("too many file label options", 0);
307 edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */
308 show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */
309 flagging |= ~incompat & merge;
311 if (incompat > 1 /* Ensure at most one of -AeExX3. */
312 || finalwrite & merge /* -i -m would rewrite input file. */
313 || (tag_count && ! flagging)) /* -L requires one of -AEX. */
314 try_help ("incompatible options", 0);
316 if (argc - optind != 3)
318 if (argc - optind < 3)
319 try_help ("missing operand after `%s'", argv[argc - 1]);
321 try_help ("extra operand `%s'", argv[optind + 3]);
324 file = &argv[optind];
326 for (i = tag_count; i < 3; i++)
327 tag_strings[i] = file[i];
329 /* Always compare file1 to file2, even if file2 is "-".
330 This is needed for -mAeExX3. Using the file0 as
331 the common file would produce wrong results, because if the
332 file0-file1 diffs didn't line up with the file0-file2 diffs
333 (which is entirely possible since we don't use diff's -n option),
334 diff3 might report phantom changes from file1 to file2.
336 Also, try to compare file0 to file1, because this is where
337 changes are expected to come from. Diffing between these pairs
338 of files is more likely to avoid phantom changes from file0 to file1.
340 Historically, the default common file was file2, so some older
341 applications (e.g. Emacs ediff) used file2 as the ancestor. So,
342 for compatibility, if this is a 3-way diff (not a merge or
343 edscript), prefer file2 as the common file. */
345 common = 2 - (edscript | merge);
347 if (STREQ (file[common], "-"))
349 /* Sigh. We've got standard input as the common file. We can't
350 call diff twice on stdin. Use the other arg as the common
353 if (STREQ (file[0], "-") || STREQ (file[common], "-"))
354 fatal ("`-' specified for more than one input file");
358 mapping[1] = 3 - common;
361 for (i = 0; i < 3; i++)
362 rev_mapping[mapping[i]] = i;
364 for (i = 0; i < 3; i++)
365 if (strcmp (file[i], "-") != 0)
367 if (stat (file[i], &statb) < 0)
368 perror_with_exit (file[i]);
369 else if (S_ISDIR (statb.st_mode))
370 error (EXIT_TROUBLE, EISDIR, "%s", file[i]);
374 /* System V fork+wait does not work if SIGCHLD is ignored. */
375 signal (SIGCHLD, SIG_DFL);
378 /* Invoke diff twice on two pairs of input files, combine the two
379 diffs, and output them. */
381 commonname = file[rev_mapping[FILEC]];
382 thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
383 thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block);
384 diff3 = make_3way_diff (thread0, thread1);
387 = output_diff3_edscript (stdout, diff3, mapping, rev_mapping,
388 tag_strings[0], tag_strings[1], tag_strings[2]);
391 xfreopen (file[rev_mapping[FILE0]], "r", stdin);
393 = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping,
394 tag_strings[0], tag_strings[1], tag_strings[2]);
396 fatal ("read failed");
400 output_diff3 (stdout, diff3, mapping, rev_mapping);
401 conflicts_found = false;
405 exit (conflicts_found);
406 return conflicts_found;
410 try_help (char const *reason_msgid, char const *operand)
413 error (0, 0, _(reason_msgid), operand);
414 error (EXIT_TROUBLE, 0,
415 _("Try `%s --help' for more information."), program_name);
423 fatal ("write failed");
424 else if (fclose (stdout) != 0)
425 perror_with_exit (_("standard output"));
428 static char const * const option_help_msgid[] = {
429 N_("-e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE."),
430 N_("-E --show-overlap Output unmerged changes, bracketing conflicts."),
431 N_("-A --show-all Output all changes, bracketing conflicts."),
432 N_("-x --overlap-only Output overlapping changes."),
433 N_("-X Output overlapping changes, bracketing them."),
434 N_("-3 --easy-only Output unmerged nonoverlapping changes."),
436 N_("-m --merge Output merged file instead of ed script (default -A)."),
437 N_("-L LABEL --label=LABEL Use LABEL instead of file name."),
438 N_("-i Append `w' and `q' commands to ed scripts."),
439 N_("-a --text Treat all files as text."),
440 N_("--strip-trailing-cr Strip trailing carriage return on input."),
441 N_("-T --initial-tab Make tabs line up by prepending a tab."),
442 N_("--diff-program=PROGRAM Use PROGRAM to compare files."),
444 N_("-v --version Output version info."),
445 N_("--help Output this help."),
452 char const * const *p;
454 printf (_("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n"),
456 printf ("%s\n\n", _("Compare three files line by line."));
457 for (p = option_help_msgid; *p; p++)
459 printf (" %s\n", _(*p));
462 printf ("\n%s\n%s\n",
463 _("If a FILE is `-', read standard input."),
464 _("Exit status is 0 if successful, 1 if conflicts, 2 if trouble."));
465 emit_bug_reporting_address ();
468 /* Combine the two diffs together into one.
469 Here is the algorithm:
471 File2 is shared in common between the two diffs.
472 Diff02 is the diff between 0 and 2.
473 Diff12 is the diff between 1 and 2.
475 1) Find the range for the first block in File2.
476 a) Take the lowest of the two ranges (in File2) in the two
477 current blocks (one from each diff) as being the low
478 water mark. Assign the upper end of this block as
479 being the high water mark and move the current block up
480 one. Mark the block just moved over as to be used.
481 b) Check the next block in the diff that the high water
484 *If* the high water mark is above
485 the low end of the range in that block,
487 mark that block as to be used and move the current
488 block up. Set the high water mark to the max of
489 the high end of this block and the current. Repeat b.
491 2) Find the corresponding ranges in File0 (from the blocks
492 in diff02; line per line outside of diffs) and in File1.
493 Create a diff3_block, reserving space as indicated by the ranges.
495 3) Copy all of the pointers for file2 in. At least for now,
496 do memcmp's between corresponding strings in the two diffs.
498 4) Copy all of the pointers for file0 and 1 in. Get what is
499 needed from file2 (when there isn't a diff block, it's
500 identical to file2 within the range between diff blocks).
502 5) If the diff blocks used came from only one of the two
503 strings of diffs, then that file (i.e. the one other than
504 the common file in that diff) is the odd person out. If
505 diff blocks are used from both sets, check to see if files
508 Same number of lines? If so, do a set of memcmp's (if
509 a memcmp matches; copy the pointer over; it'll be easier
510 later during comparisons). If they match, 0 & 1 are the
511 same. If not, all three different.
513 Then do it again, until the blocks are exhausted. */
516 /* Make a three way diff (chain of diff3_block's) from two two way
517 diffs (chains of diff_block's). Assume that each of the two diffs
518 passed are onto the same file (i.e. that each of the diffs were
519 made "to" the same file). Return a three way diff pointer with
520 numbering FILE0 = the other file in diff02, FILE1 = the other file
521 in diff12, and FILEC = the common file. */
523 static struct diff3_block *
524 make_3way_diff (struct diff_block *thread0, struct diff_block *thread1)
526 /* Work on the two diffs passed to it as threads. Thread number 0
527 is diff02, thread number 1 is diff12. USING is the base of the
528 list of blocks to be used to construct each block of the three
529 way diff; if no blocks from a particular thread are to be used,
530 that element of USING is 0. LAST_USING contains the last
531 elements on each of the using lists.
533 HIGH_WATER_MARK is the highest line number in the common file
534 described in any of the diffs in either of the USING lists.
535 HIGH_WATER_THREAD names the thread. Similarly BASE_WATER_MARK
536 and BASE_WATER_THREAD describe the lowest line number in the
537 common file described in any of the diffs in either of the USING
538 lists. HIGH_WATER_DIFF is the diff from which the
539 HIGH_WATER_MARK was taken.
541 HIGH_WATER_DIFF should always be equal to
542 LAST_USING[HIGH_WATER_THREAD]. OTHER_DIFF is the next diff to
543 check for higher water, and should always be equal to
544 CURRENT[HIGH_WATER_THREAD ^ 1]. OTHER_THREAD is the thread in
545 which the OTHER_DIFF is, and hence should always be equal to
546 HIGH_WATER_THREAD ^ 1.
548 LAST_DIFF is the last diff block produced by this routine, for
549 line correspondence purposes between that diff and the one
550 currently being worked on. It is ZERO_DIFF before any blocks
551 have been created. */
553 struct diff_block *using[2];
554 struct diff_block *last_using[2];
555 struct diff_block *current[2];
559 int high_water_thread;
560 int base_water_thread;
563 struct diff_block *high_water_diff;
564 struct diff_block *other_diff;
566 struct diff3_block *result;
567 struct diff3_block *tmpblock;
568 struct diff3_block **result_end;
570 struct diff3_block const *last_diff3;
572 static struct diff3_block const zero_diff3;
576 result_end = &result;
577 current[0] = thread0; current[1] = thread1;
578 last_diff3 = &zero_diff3;
580 /* Sniff up the threads until we reach the end */
582 while (current[0] || current[1])
584 using[0] = using[1] = last_using[0] = last_using[1] = 0;
586 /* Setup low and high water threads, diffs, and marks. */
588 base_water_thread = 1;
589 else if (!current[1])
590 base_water_thread = 0;
593 (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
595 high_water_thread = base_water_thread;
597 high_water_diff = current[high_water_thread];
599 high_water_mark = D_HIGHLINE (high_water_diff, FC);
601 /* Make the diff you just got info from into the using class */
602 using[high_water_thread]
603 = last_using[high_water_thread]
605 current[high_water_thread] = high_water_diff->next;
606 last_using[high_water_thread]->next = 0;
608 /* And mark the other diff */
609 other_thread = high_water_thread ^ 0x1;
610 other_diff = current[other_thread];
612 /* Shuffle up the ladder, checking the other diff to see if it
613 needs to be incorporated. */
615 && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
618 /* Incorporate this diff into the using list. Note that
619 this doesn't take it off the current list */
620 if (using[other_thread])
621 last_using[other_thread]->next = other_diff;
623 using[other_thread] = other_diff;
624 last_using[other_thread] = other_diff;
626 /* Take it off the current list. Note that this following
627 code assumes that other_diff enters it equal to
628 current[high_water_thread ^ 0x1] */
629 current[other_thread] = current[other_thread]->next;
630 other_diff->next = 0;
632 /* Set the high_water stuff
633 If this comparison is equal, then this is the last pass
634 through this loop; since diff blocks within a given
635 thread cannot overlap, the high_water_mark will be
636 *below* the range_start of either of the next diffs. */
638 if (high_water_mark < D_HIGHLINE (other_diff, FC))
640 high_water_thread ^= 1;
641 high_water_mark = D_HIGHLINE (other_diff, FC);
644 /* Set the other diff */
645 other_thread = high_water_thread ^ 0x1;
646 other_diff = current[other_thread];
649 /* The using lists contain a list of all of the blocks to be
650 included in this diff3_block. Create it. */
652 tmpblock = using_to_diff3_block (using, last_using,
653 base_water_thread, high_water_thread,
657 fatal ("internal error: screwup in format of diff blocks");
659 /* Put it on the list. */
660 *result_end = tmpblock;
661 result_end = &tmpblock->next;
663 /* Set up corresponding lines correctly. */
664 last_diff3 = tmpblock;
669 /* Take two lists of blocks (from two separate diff threads) and put
670 them together into one diff3 block. Return a pointer to this diff3
671 block or 0 for failure.
673 All arguments besides using are for the convenience of the routine;
674 they could be derived from the using array. LAST_USING is a pair
675 of pointers to the last blocks in the using structure. LOW_THREAD
676 and HIGH_THREAD tell which threads contain the lowest and highest
677 line numbers for File0. LAST_DIFF3 contains the last diff produced
678 in the calling routine. This is used for lines mappings that
679 would still be identical to the state that diff ended in.
681 A distinction should be made in this routine between the two diffs
682 that are part of a normal two diff block, and the three diffs that
683 are part of a diff3_block. */
685 static struct diff3_block *
686 using_to_diff3_block (struct diff_block *using[2],
687 struct diff_block *last_using[2],
688 int low_thread, int high_thread,
689 struct diff3_block const *last_diff3)
692 struct diff3_block *result;
693 struct diff_block *ptr;
697 /* Find the range in the common file. */
698 lin lowc = D_LOWLINE (using[low_thread], FC);
699 lin highc = D_HIGHLINE (last_using[high_thread], FC);
701 /* Find the ranges in the other files.
702 If using[d] is null, that means that the file to which that diff
703 refers is equivalent to the common file over this range. */
705 for (d = 0; d < 2; d++)
708 low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
709 high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
713 low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
714 high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
717 /* Create a block with the appropriate sizes */
718 result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
720 /* Copy information for the common file.
721 Return with a zero if any of the compares failed. */
723 for (d = 0; d < 2; d++)
724 for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
726 lin result_offset = D_LOWLINE (ptr, FC) - lowc;
728 if (!copy_stringlist (D_LINEARRAY (ptr, FC),
729 D_LENARRAY (ptr, FC),
730 D_LINEARRAY (result, FILEC) + result_offset,
731 D_LENARRAY (result, FILEC) + result_offset,
732 D_NUMLINES (ptr, FC)))
736 /* Copy information for file d. First deal with anything that might be
737 before the first diff. */
739 for (d = 0; d < 2; d++)
741 struct diff_block *u = using[d];
742 lin lo = low[d], hi = high[d];
745 i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
748 D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
749 D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
752 for (ptr = u; ptr; ptr = D_NEXT (ptr))
754 lin result_offset = D_LOWLINE (ptr, FO) - lo;
757 if (!copy_stringlist (D_LINEARRAY (ptr, FO),
758 D_LENARRAY (ptr, FO),
759 D_LINEARRAY (result, FILE0 + d) + result_offset,
760 D_LENARRAY (result, FILE0 + d) + result_offset,
761 D_NUMLINES (ptr, FO)))
764 /* Catch the lines between here and the next diff */
765 linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
766 for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
767 i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
770 D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
771 D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
779 D3_TYPE (result) = DIFF_2ND;
781 D3_TYPE (result) = DIFF_1ST;
784 lin nl0 = D_NUMLINES (result, FILE0);
785 lin nl1 = D_NUMLINES (result, FILE1);
788 || !compare_line_list (D_LINEARRAY (result, FILE0),
789 D_LENARRAY (result, FILE0),
790 D_LINEARRAY (result, FILE1),
791 D_LENARRAY (result, FILE1),
793 D3_TYPE (result) = DIFF_ALL;
795 D3_TYPE (result) = DIFF_3RD;
801 /* Copy pointers from a list of strings to a different list of
802 strings. If a spot in the second list is already filled, make sure
803 that it is filled with the same string; if not, return false, the copy
804 incomplete. Upon successful completion of the copy, return true. */
807 copy_stringlist (char * const fromptrs[], size_t const fromlengths[],
808 char *toptrs[], size_t tolengths[],
811 register char * const *f = fromptrs;
812 register char **t = toptrs;
813 register size_t const *fl = fromlengths;
814 register size_t *tl = tolengths;
820 if (*fl != *tl || memcmp (*f, *t, *fl) != 0)
829 t++; f++; tl++; fl++;
835 /* Create a diff3_block, with ranges as specified in the arguments.
836 Allocate the arrays for the various pointers (and zero them) based
837 on the arguments passed. Return the block as a result. */
839 static struct diff3_block *
840 create_diff3_block (lin low0, lin high0,
844 struct diff3_block *result = xmalloc (sizeof *result);
847 D3_TYPE (result) = ERROR;
851 D_LOWLINE (result, FILE0) = low0;
852 D_HIGHLINE (result, FILE0) = high0;
853 D_LOWLINE (result, FILE1) = low1;
854 D_HIGHLINE (result, FILE1) = high1;
855 D_LOWLINE (result, FILE2) = low2;
856 D_HIGHLINE (result, FILE2) = high2;
858 /* Allocate and zero space */
859 numlines = D_NUMLINES (result, FILE0);
862 D_LINEARRAY (result, FILE0) = xcalloc (numlines, sizeof (char *));
863 D_LENARRAY (result, FILE0) = xcalloc (numlines, sizeof (size_t));
867 D_LINEARRAY (result, FILE0) = 0;
868 D_LENARRAY (result, FILE0) = 0;
871 numlines = D_NUMLINES (result, FILE1);
874 D_LINEARRAY (result, FILE1) = xcalloc (numlines, sizeof (char *));
875 D_LENARRAY (result, FILE1) = xcalloc (numlines, sizeof (size_t));
879 D_LINEARRAY (result, FILE1) = 0;
880 D_LENARRAY (result, FILE1) = 0;
883 numlines = D_NUMLINES (result, FILE2);
886 D_LINEARRAY (result, FILE2) = xcalloc (numlines, sizeof (char *));
887 D_LENARRAY (result, FILE2) = xcalloc (numlines, sizeof (size_t));
891 D_LINEARRAY (result, FILE2) = 0;
892 D_LENARRAY (result, FILE2) = 0;
899 /* Compare two lists of lines of text.
900 Return 1 if they are equivalent, 0 if not. */
903 compare_line_list (char * const list1[], size_t const lengths1[],
904 char * const list2[], size_t const lengths2[],
907 char * const *l1 = list1;
908 char * const *l2 = list2;
909 size_t const *lgths1 = lengths1;
910 size_t const *lgths2 = lengths2;
913 if (!*l1 || !*l2 || *lgths1 != *lgths2++
914 || memcmp (*l1++, *l2++, *lgths1++) != 0)
919 /* Input and parse two way diffs. */
921 static struct diff_block *
922 process_diff (char const *filea,
924 struct diff_block **last_block)
931 struct diff_block *block_list;
932 struct diff_block **block_list_end = &block_list;
933 struct diff_block *bptr IF_LINT (= NULL);
934 size_t too_many_lines = (PTRDIFF_MAX
935 / MIN (sizeof *bptr->lines[1],
936 sizeof *bptr->lengths[1]));
938 diff_limit = read_diff (filea, fileb, &diff_contents);
939 scan_diff = diff_contents;
941 while (scan_diff < diff_limit)
943 bptr = xmalloc (sizeof *bptr);
944 bptr->lines[0] = bptr->lines[1] = 0;
945 bptr->lengths[0] = bptr->lengths[1] = 0;
947 dt = process_diff_control (&scan_diff, bptr);
948 if (dt == ERROR || *scan_diff != '\n')
950 fprintf (stderr, _("%s: diff failed: "), program_name);
953 putc (*scan_diff, stderr);
955 while (*scan_diff++ != '\n');
960 /* Force appropriate ranges to be null, if necessary */
964 bptr->ranges[0][0]++;
967 bptr->ranges[1][0]++;
972 fatal ("internal error: invalid diff type in process_diff");
976 /* Allocate space for the pointers for the lines from filea, and
977 parcel them out among these pointers */
980 lin numlines = D_NUMLINES (bptr, 0);
981 if (too_many_lines <= numlines)
983 bptr->lines[0] = xmalloc (numlines * sizeof *bptr->lines[0]);
984 bptr->lengths[0] = xmalloc (numlines * sizeof *bptr->lengths[0]);
985 for (i = 0; i < numlines; i++)
986 scan_diff = scan_diff_line (scan_diff,
987 &(bptr->lines[0][i]),
988 &(bptr->lengths[0][i]),
993 /* Get past the separator for changes */
996 if (strncmp (scan_diff, "---\n", 4))
997 fatal ("invalid diff format; invalid change separator");
1001 /* Allocate space for the pointers for the lines from fileb, and
1002 parcel them out among these pointers */
1005 lin numlines = D_NUMLINES (bptr, 1);
1006 if (too_many_lines <= numlines)
1008 bptr->lines[1] = xmalloc (numlines * sizeof *bptr->lines[1]);
1009 bptr->lengths[1] = xmalloc (numlines * sizeof *bptr->lengths[1]);
1010 for (i = 0; i < numlines; i++)
1011 scan_diff = scan_diff_line (scan_diff,
1012 &(bptr->lines[1][i]),
1013 &(bptr->lengths[1][i]),
1018 /* Place this block on the blocklist. */
1019 *block_list_end = bptr;
1020 block_list_end = &bptr->next;
1023 *block_list_end = NULL;
1028 /* Skip tabs and spaces, and return the first character after them. */
1033 while (*s == ' ' || *s == '\t')
1038 /* Read a nonnegative line number from S, returning the address of the
1039 first character after the line number, and storing the number into
1040 *PNUM. Return 0 if S does not point to a valid line number. */
1043 readnum (char *s, lin *pnum)
1045 unsigned char c = *s;
1053 num = c - '0' + num * 10;
1056 while (ISDIGIT (c));
1062 /* Parse a normal format diff control string. Return the type of the
1063 diff (ERROR if the format is bad). All of the other important
1064 information is filled into to the structure pointed to by db, and
1065 the string pointer (whose location is passed to this routine) is
1066 updated to point beyond the end of the string parsed. Note that
1067 only the ranges in the diff_block will be set by this routine.
1069 If some specific pair of numbers has been reduced to a single
1070 number, then both corresponding numbers in the diff block are set
1071 to that number. In general these numbers are interpreted as ranges
1072 inclusive, unless being used by the ADD or DELETE commands. It is
1073 assumed that these will be special cased in a superior routine. */
1075 static enum diff_type
1076 process_diff_control (char **string, struct diff_block *db)
1079 enum diff_type type;
1081 /* Read first set of digits */
1082 s = readnum (skipwhite (s), &db->ranges[0][RANGE_START]);
1086 /* Was that the only digit? */
1090 s = readnum (s + 1, &db->ranges[0][RANGE_END]);
1095 db->ranges[0][RANGE_END] = db->ranges[0][RANGE_START];
1097 /* Get the letter */
1111 return ERROR; /* Bad format */
1113 s++; /* Past letter */
1115 /* Read second set of digits */
1116 s = readnum (skipwhite (s), &db->ranges[1][RANGE_START]);
1120 /* Was that the only digit? */
1124 s = readnum (s + 1, &db->ranges[1][RANGE_END]);
1127 s = skipwhite (s); /* To move to end */
1130 db->ranges[1][RANGE_END] = db->ranges[1][RANGE_START];
1137 read_diff (char const *filea,
1139 char **output_placement)
1142 size_t current_chunk_size, total;
1143 int fd, wstatus, status;
1145 struct stat pipestat;
1147 #if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
1149 char const *argv[9];
1155 *ap++ = diff_program;
1158 if (strip_trailing_cr)
1159 *ap++ = "--strip-trailing-cr";
1160 *ap++ = "--horizon-lines=100";
1166 if (pipe (fds) != 0)
1167 perror_with_exit ("pipe");
1174 if (fds[1] != STDOUT_FILENO)
1176 dup2 (fds[1], STDOUT_FILENO);
1180 /* The cast to (char **) is needed for portability to older
1181 hosts with a nonstandard prototype for execvp. */
1182 execvp (diff_program, (char **) argv);
1184 _exit (errno == ENOENT ? 127 : 126);
1188 perror_with_exit ("fork");
1190 close (fds[1]); /* Prevent erroneous lack of EOF */
1196 char const args[] = " --horizon-lines=100 -- ";
1197 char *command = xmalloc (shell_quote_length (diff_program)
1199 + sizeof "--strip-trailing-cr"
1201 + shell_quote_length (filea) + 1
1202 + shell_quote_length (fileb) + 1);
1204 p = shell_quote_copy (p, diff_program);
1210 if (strip_trailing_cr)
1212 strcpy (p, " --strip-trailing-cr");
1216 p += sizeof args - 1;
1217 p = shell_quote_copy (p, filea);
1219 p = shell_quote_copy (p, fileb);
1222 fpipe = popen (command, "r");
1224 perror_with_exit (command);
1226 fd = fileno (fpipe);
1230 if (fstat (fd, &pipestat) != 0)
1231 perror_with_exit ("fstat");
1232 current_chunk_size = MAX (1, STAT_BLOCKSIZE (pipestat));
1233 diff_result = xmalloc (current_chunk_size);
1238 size_t bytes_to_read = current_chunk_size - total;
1239 size_t bytes = block_read (fd, diff_result + total, bytes_to_read);
1241 if (bytes != bytes_to_read)
1243 if (bytes == SIZE_MAX)
1244 perror_with_exit (_("read failed"));
1247 if (PTRDIFF_MAX / 2 <= current_chunk_size)
1249 current_chunk_size *= 2;
1250 diff_result = xrealloc (diff_result, current_chunk_size);
1253 if (total != 0 && diff_result[total-1] != '\n')
1254 fatal ("invalid diff format; incomplete last line");
1256 *output_placement = diff_result;
1258 #if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
1260 wstatus = pclose (fpipe);
1266 if (close (fd) != 0)
1267 perror_with_exit ("close");
1268 if (waitpid (pid, &wstatus, 0) < 0)
1269 perror_with_exit ("waitpid");
1273 status = ! werrno && WIFEXITED (wstatus) ? WEXITSTATUS (wstatus) : INT_MAX;
1275 if (EXIT_TROUBLE <= status)
1276 error (EXIT_TROUBLE, werrno,
1278 ? "subsidiary program `%s' could not be invoked"
1280 ? "subsidiary program `%s' not found"
1282 ? "subsidiary program `%s' failed"
1283 : "subsidiary program `%s' failed (exit status %d)"),
1284 diff_program, status);
1286 return diff_result + total;
1290 /* Scan a regular diff line (consisting of > or <, followed by a
1291 space, followed by text (including nulls) up to a newline.
1293 This next routine began life as a macro and many parameters in it
1294 are used as call-by-reference values. */
1296 scan_diff_line (char *scan_ptr, char **set_start, size_t *set_length,
1297 char *limit, char leadingchar)
1301 if (!(scan_ptr[0] == leadingchar
1302 && scan_ptr[1] == ' '))
1303 fatal ("invalid diff format; incorrect leading line chars");
1305 *set_start = line_ptr = scan_ptr + 2;
1306 while (*line_ptr++ != '\n')
1309 /* Include newline if the original line ended in a newline,
1310 or if an edit script is being generated.
1311 Copy any missing newline message to stderr if an edit script is being
1312 generated, because edit scripts cannot handle missing newlines.
1313 Return the beginning of the next line. */
1314 *set_length = line_ptr - *set_start;
1315 if (line_ptr < limit && *line_ptr == '\\')
1318 fprintf (stderr, "%s:", program_name);
1325 putc (*line_ptr, stderr);
1327 while (*line_ptr++ != '\n');
1333 /* Output a three way diff passed as a list of diff3_block's. The
1334 argument MAPPING is indexed by external file number (in the
1335 argument list) and contains the internal file number (from the diff
1336 passed). This is important because the user expects outputs in
1337 terms of the argument list number, and the diff passed may have
1338 been done slightly differently (if the last argument was "-", for
1339 example). REV_MAPPING is the inverse of MAPPING. */
1342 output_diff3 (FILE *outputfile, struct diff3_block *diff,
1343 int const mapping[3], int const rev_mapping[3])
1348 struct diff3_block *ptr;
1352 static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
1353 char const *line_prefix = initial_tab ? "\t" : " ";
1355 for (ptr = diff; ptr; ptr = D_NEXT (ptr))
1359 switch (ptr->correspond)
1363 dontprint = 3; /* Print them all */
1364 oddoneout = 3; /* Nobody's odder than anyone else */
1369 oddoneout = rev_mapping[ptr->correspond - DIFF_1ST];
1371 x[0] = oddoneout + '1';
1373 dontprint = oddoneout == 0;
1376 fatal ("internal error: invalid diff type passed to output");
1378 fprintf (outputfile, "====%s\n", x);
1380 /* Go 0, 2, 1 if the first and third outputs are equivalent. */
1382 i = (oddoneout == 1 ? skew_increment[i] : i + 1))
1384 int realfile = mapping[i];
1385 lin lowt = D_LOWLINE (ptr, realfile);
1386 lin hight = D_HIGHLINE (ptr, realfile);
1387 long int llowt = lowt;
1388 long int lhight = hight;
1390 fprintf (outputfile, "%d:", i + 1);
1391 switch (lowt - hight)
1394 fprintf (outputfile, "%lda\n", llowt - 1);
1397 fprintf (outputfile, "%ldc\n", llowt);
1400 fprintf (outputfile, "%ld,%ldc\n", llowt, lhight);
1404 if (i == dontprint) continue;
1411 fputs (line_prefix, outputfile);
1412 cp = D_RELNUM (ptr, realfile, line);
1413 length = D_RELLEN (ptr, realfile, line);
1414 fwrite (cp, sizeof (char), length, outputfile);
1416 while (++line < hight - lowt + 1);
1417 if (cp[length - 1] != '\n')
1418 fprintf (outputfile, "\n\\ %s\n",
1419 _("No newline at end of file"));
1426 /* Output to OUTPUTFILE the lines of B taken from FILENUM. Double any
1427 initial '.'s; yield nonzero if any initial '.'s were doubled. */
1430 dotlines (FILE *outputfile, struct diff3_block *b, int filenum)
1433 bool leading_dot = false;
1436 i < D_NUMLINES (b, filenum);
1439 char *line = D_RELNUM (b, filenum, i);
1443 fputc ('.', outputfile);
1445 fwrite (line, sizeof (char),
1446 D_RELLEN (b, filenum, i), outputfile);
1452 /* Output to OUTPUTFILE a '.' line. If LEADING_DOT is true, also
1453 output a command that removes initial '.'s starting with line START
1454 and continuing for NUM lines. (START is long int, not lin, for
1455 convenience with printf %ld formats.) */
1458 undotlines (FILE *outputfile, bool leading_dot, long int start, lin num)
1460 fputs (".\n", outputfile);
1464 fprintf (outputfile, "%lds/^\\.//\n", start);
1466 fprintf (outputfile, "%ld,%lds/^\\.//\n", start, start + num - 1);
1470 /* Output a diff3 set of blocks as an ed script. This script applies
1471 the changes between file's 2 & 3 to file 1. Take the precise
1472 format of the ed script to be output from global variables set
1473 during options processing. Reverse the order of
1474 the set of diff3 blocks in DIFF; this gets
1475 around the problems involved with changing line numbers in an ed
1478 As in `output_diff3', the variable MAPPING maps from file number
1479 according to the argument list to file number according to the diff
1480 passed. All files listed below are in terms of the argument list.
1481 REV_MAPPING is the inverse of MAPPING.
1483 FILE0, FILE1 and FILE2 are the strings to print as the names of the
1484 three files. These may be the actual names, or may be the
1485 arguments specified with -L.
1487 Return 1 if conflicts were found. */
1490 output_diff3_edscript (FILE *outputfile, struct diff3_block *diff,
1491 int const mapping[3], int const rev_mapping[3],
1492 char const *file0, char const *file1, char const *file2)
1495 bool conflicts_found = false;
1497 struct diff3_block *b;
1499 for (b = reverse_diff3_blocklist (diff); b; b = b->next)
1501 /* Must do mapping correctly. */
1503 = (b->correspond == DIFF_ALL
1505 : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
1507 long int low0, high0;
1509 /* If we aren't supposed to do this output block, skip it. */
1513 case DIFF_2ND: if (!show_2nd) continue; conflict = true; break;
1514 case DIFF_3RD: if (overlap_only) continue; conflict = false; break;
1515 case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
1518 low0 = D_LOWLINE (b, mapping[FILE0]);
1519 high0 = D_HIGHLINE (b, mapping[FILE0]);
1523 conflicts_found = true;
1526 /* Mark end of conflict. */
1528 fprintf (outputfile, "%lda\n", high0);
1529 leading_dot = false;
1530 if (type == DIFF_ALL)
1534 /* Append lines from FILE1. */
1535 fprintf (outputfile, "||||||| %s\n", file1);
1536 leading_dot = dotlines (outputfile, b, mapping[FILE1]);
1538 /* Append lines from FILE2. */
1539 fputs ("=======\n", outputfile);
1540 leading_dot |= dotlines (outputfile, b, mapping[FILE2]);
1542 fprintf (outputfile, ">>>>>>> %s\n", file2);
1543 undotlines (outputfile, leading_dot, high0 + 2,
1544 (D_NUMLINES (b, mapping[FILE1])
1545 + D_NUMLINES (b, mapping[FILE2]) + 1));
1548 /* Mark start of conflict. */
1550 fprintf (outputfile, "%lda\n<<<<<<< %s\n", low0 - 1,
1551 type == DIFF_ALL ? file0 : file1);
1552 leading_dot = false;
1553 if (type == DIFF_2ND)
1555 /* Prepend lines from FILE1. */
1556 leading_dot = dotlines (outputfile, b, mapping[FILE1]);
1557 fputs ("=======\n", outputfile);
1559 undotlines (outputfile, leading_dot, low0 + 1,
1560 D_NUMLINES (b, mapping[FILE1]));
1562 else if (D_NUMLINES (b, mapping[FILE2]) == 0)
1563 /* Write out a delete */
1566 fprintf (outputfile, "%ldd\n", low0);
1568 fprintf (outputfile, "%ld,%ldd\n", low0, high0);
1571 /* Write out an add or change */
1573 switch (high0 - low0)
1576 fprintf (outputfile, "%lda\n", high0);
1579 fprintf (outputfile, "%ldc\n", high0);
1582 fprintf (outputfile, "%ld,%ldc\n", low0, high0);
1586 undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]),
1587 low0, D_NUMLINES (b, mapping[FILE2]));
1591 fputs ("w\nq\n", outputfile);
1592 return conflicts_found;
1595 /* Read from INFILE and output to OUTPUTFILE a set of diff3_blocks
1596 DIFF as a merged file. This acts like 'ed file0
1597 <[output_diff3_edscript]', except that it works even for binary
1598 data or incomplete lines.
1600 As before, MAPPING maps from arg list file number to diff file
1601 number, REV_MAPPING is its inverse, and FILE0, FILE1, and FILE2 are
1602 the names of the files.
1604 Return 1 if conflicts were found. */
1607 output_diff3_merge (FILE *infile, FILE *outputfile, struct diff3_block *diff,
1608 int const mapping[3], int const rev_mapping[3],
1609 char const *file0, char const *file1, char const *file2)
1613 bool conflicts_found = false;
1615 struct diff3_block *b;
1618 for (b = diff; b; b = b->next)
1620 /* Must do mapping correctly. */
1622 = ((b->correspond == DIFF_ALL)
1624 : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
1625 char const *format_2nd = "<<<<<<< %s\n";
1627 /* If we aren't supposed to do this output block, skip it. */
1631 case DIFF_2ND: if (!show_2nd) continue; conflict = true; break;
1632 case DIFF_3RD: if (overlap_only) continue; conflict = false; break;
1633 case DIFF_ALL: if (simple_only) continue; conflict = flagging;
1634 format_2nd = "||||||| %s\n";
1638 /* Copy I lines from file 0. */
1639 i = D_LOWLINE (b, FILE0) - linesread - 1;
1647 if (ferror (infile))
1648 perror_with_exit (_("read failed"));
1649 else if (feof (infile))
1650 fatal ("input file shrank");
1652 putc (c, outputfile);
1658 conflicts_found = true;
1660 if (type == DIFF_ALL)
1662 /* Put in lines from FILE0 with bracket. */
1663 fprintf (outputfile, "<<<<<<< %s\n", file0);
1665 i < D_NUMLINES (b, mapping[FILE0]);
1667 fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
1668 D_RELLEN (b, mapping[FILE0], i), outputfile);
1673 /* Put in lines from FILE1 with bracket. */
1674 fprintf (outputfile, format_2nd, file1);
1676 i < D_NUMLINES (b, mapping[FILE1]);
1678 fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char),
1679 D_RELLEN (b, mapping[FILE1], i), outputfile);
1682 fputs ("=======\n", outputfile);
1685 /* Put in lines from FILE2. */
1687 i < D_NUMLINES (b, mapping[FILE2]);
1689 fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
1690 D_RELLEN (b, mapping[FILE2], i), outputfile);
1693 fprintf (outputfile, ">>>>>>> %s\n", file2);
1695 /* Skip I lines in file 0. */
1696 i = D_NUMLINES (b, FILE0);
1699 while ((c = getc (infile)) != '\n')
1702 if (ferror (infile))
1703 perror_with_exit (_("read failed"));
1704 else if (feof (infile))
1707 fatal ("input file shrank");
1708 return conflicts_found;
1712 /* Copy rest of common file. */
1713 while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
1714 putc (c, outputfile);
1715 return conflicts_found;
1718 /* Reverse the order of the list of diff3 blocks. */
1720 static struct diff3_block *
1721 reverse_diff3_blocklist (struct diff3_block *diff)
1723 register struct diff3_block *tmp, *next, *prev;
1725 for (tmp = diff, prev = 0; tmp; tmp = next)
1736 fatal (char const *msgid)
1738 error (EXIT_TROUBLE, 0, "%s", _(msgid));
1743 perror_with_exit (char const *string)
1745 error (EXIT_TROUBLE, errno, "%s", string);