3 /* diff3 - compare three files line by line
5 Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1998, 2001,
6 2002 Free Software Foundation, Inc.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 See the GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING.
20 If not, write to the Free Software Foundation,
21 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25 static char const copyright_string
[] =
26 "Copyright (C) 2002 Free Software Foundation, Inc.";
28 static char const authorship_msgid
[] = N_("Written by Randy Smith.");
41 extern char const version_string
[];
44 * Internal data structures and macros for the diff3 program; includes
45 * data structures for both diff3 diffs and normal diffs.
48 /* Different files within a three way diff. */
54 * A three way diff is built from two two-way diffs; the file which
55 * the two two-way diffs share is:
60 * Different files within a two way diff.
61 * FC is the common file, FO the other file.
66 /* The ranges are indexed by */
71 ERROR
, /* Should not be used */
72 ADD
, /* Two way diff add */
73 CHANGE
, /* Two way diff change */
74 DELETE
, /* Two way diff delete */
75 DIFF_ALL
, /* All three are different */
76 DIFF_1ST
, /* Only the first is different */
77 DIFF_2ND
, /* Only the second */
78 DIFF_3RD
/* Only the third */
83 lin ranges
[2][2]; /* Ranges are inclusive */
84 char **lines
[2]; /* The actual lines (may contain nulls) */
85 size_t *lengths
[2]; /* Line lengths (including newlines, if any) */
86 struct diff_block
*next
;
92 enum diff_type correspond
; /* Type of diff */
93 lin ranges
[3][2]; /* Ranges are inclusive */
94 char **lines
[3]; /* The actual lines (may contain nulls) */
95 size_t *lengths
[3]; /* Line lengths (including newlines, if any) */
96 struct diff3_block
*next
;
100 * Access the ranges on a diff block.
102 #define D_LOWLINE(diff, filenum) \
103 ((diff)->ranges[filenum][RANGE_START])
104 #define D_HIGHLINE(diff, filenum) \
105 ((diff)->ranges[filenum][RANGE_END])
106 #define D_NUMLINES(diff, filenum) \
107 (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
110 * Access the line numbers in a file in a diff by relative line
111 * numbers (i.e. line number within the diff itself). Note that these
112 * are lvalues and can be used for assignment.
114 #define D_RELNUM(diff, filenum, linenum) \
115 ((diff)->lines[filenum][linenum])
116 #define D_RELLEN(diff, filenum, linenum) \
117 ((diff)->lengths[filenum][linenum])
120 * And get at them directly, when that should be necessary.
122 #define D_LINEARRAY(diff, filenum) \
123 ((diff)->lines[filenum])
124 #define D_LENARRAY(diff, filenum) \
125 ((diff)->lengths[filenum])
130 #define D_NEXT(diff) ((diff)->next)
133 * Access the type of a diff3 block.
135 #define D3_TYPE(diff) ((diff)->correspond)
138 * Line mappings based on diffs. The first maps off the top of the
139 * diff, the second off of the bottom.
141 #define D_HIGH_MAPLINE(diff, fromfile, tofile, linenum) \
143 - D_HIGHLINE ((diff), (fromfile)) \
144 + D_HIGHLINE ((diff), (tofile)))
146 #define D_LOW_MAPLINE(diff, fromfile, tofile, linenum) \
148 - D_LOWLINE ((diff), (fromfile)) \
149 + D_LOWLINE ((diff), (tofile)))
151 /* Options variables for flags set on command line. */
153 /* If nonzero, treat all files as text files, never as binary. */
156 /* If nonzero, write out an ed script instead of the standard diff3 format. */
157 static bool edscript
;
159 /* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
160 preserve the lines which would normally be deleted from
161 file 1 with a special flagging mechanism. */
162 static bool flagging
;
164 /* Use a tab to align output lines (-T). */
165 static bool initial_tab
;
167 /* If nonzero, do not output information for overlapping diffs. */
168 static bool simple_only
;
170 /* If nonzero, do not output information for non-overlapping diffs. */
171 static bool overlap_only
;
173 /* If nonzero, show information for DIFF_2ND diffs. */
174 static bool show_2nd
;
176 /* If nonzero, include `:wq' at the end of the script
177 to write out the file being edited. */
178 static bool finalwrite
;
180 /* If nonzero, output a merged file. */
185 static char *read_diff (char const *, char const *, char **);
186 static char *scan_diff_line (char *, char **, size_t *, char *, char);
187 static enum diff_type
process_diff_control (char **, struct diff_block
*);
188 static bool compare_line_list (char * const[], size_t const[], char * const[], size_t const[], lin
);
189 static bool copy_stringlist (char * const[], size_t const[], char *[], size_t[], lin
);
190 static bool output_diff3_edscript (FILE *, struct diff3_block
*, int const[3], int const[3], char const *, char const *, char const *);
191 static bool output_diff3_merge (FILE *, FILE *, struct diff3_block
*, int const[3], int const[3], char const *, char const *, char const *);
192 static struct diff3_block
*create_diff3_block (lin
, lin
, lin
, lin
, lin
, lin
);
193 static struct diff3_block
*make_3way_diff (struct diff_block
*, struct diff_block
*);
194 static struct diff3_block
*reverse_diff3_blocklist (struct diff3_block
*);
195 static struct diff3_block
*using_to_diff3_block (struct diff_block
*[2], struct diff_block
*[2], int, int, struct diff3_block
const *);
196 static struct diff_block
*process_diff (char const *, char const *, struct diff_block
**);
197 static void check_stdout (void);
198 static void fatal (char const *) __attribute__((noreturn
));
199 static void output_diff3 (FILE *, struct diff3_block
*, int const[3], int const[3]);
200 static void perror_with_exit (char const *) __attribute__((noreturn
));
201 static void try_help (char const *, char const *) __attribute__((noreturn
));
202 static void usage (void);
204 static char const *diff_program
= DEFAULT_DIFF_PROGRAM
;
206 /* Values for long options that do not have single-letter equivalents. */
209 DIFF_PROGRAM_OPTION
= CHAR_MAX
+ 1,
213 static struct option
const longopts
[] =
216 {"show-all", 0, 0, 'A'},
218 {"diff-program", 1, 0, DIFF_PROGRAM_OPTION
},
219 {"show-overlap", 0, 0, 'E'},
220 {"label", 1, 0, 'L'},
221 {"merge", 0, 0, 'm'},
222 {"initial-tab", 0, 0, 'T'},
223 {"overlap-only", 0, 0, 'x'},
224 {"easy-only", 0, 0, '3'},
225 {"version", 0, 0, 'v'},
226 {"help", 0, 0, HELP_OPTION
},
231 * Main program. Calls diff twice on two pairs of input files,
232 * combines the two diffs, and outputs them.
235 main (int argc
, char **argv
)
242 bool conflicts_found
;
243 struct diff_block
*thread0
, *thread1
, *last_block
;
244 struct diff3_block
*diff3
;
246 char *tag_strings
[3];
252 initialize_main (&argc
, &argv
);
253 program_name
= argv
[0];
254 setlocale (LC_ALL
, "");
255 bindtextdomain (PACKAGE
, LOCALEDIR
);
256 textdomain (PACKAGE
);
257 c_stack_action (c_stack_die
);
259 while ((c
= getopt_long (argc
, argv
, "aeimvx3AEL:TX", longopts
, 0)) != -1)
298 printf ("diff3 %s\n%s\n\n%s\n\n%s\n",
299 version_string
, copyright_string
,
300 _(free_software_msgid
), _(authorship_msgid
));
303 case DIFF_PROGRAM_OPTION
:
304 diff_program
= optarg
;
311 /* Handle up to three -L options. */
314 tag_strings
[tag_count
++] = optarg
;
317 try_help ("too many file label options", 0);
323 edscript
= incompat
& ~merge
; /* -AeExX3 without -m implies ed script. */
324 show_2nd
|= ~incompat
& merge
; /* -m without -AeExX3 implies -A. */
325 flagging
|= ~incompat
& merge
;
327 if (incompat
> 1 /* Ensure at most one of -AeExX3. */
328 || finalwrite
& merge
/* -i -m would rewrite input file. */
329 || (tag_count
&& ! flagging
)) /* -L requires one of -AEX. */
330 try_help ("incompatible options", 0);
332 if (argc
- optind
!= 3)
334 if (argc
- optind
< 3)
335 try_help ("missing operand after `%s'", argv
[argc
- 1]);
337 try_help ("extra operand `%s'", argv
[optind
+ 3]);
340 file
= &argv
[optind
];
342 for (i
= tag_count
; i
< 3; i
++)
343 tag_strings
[i
] = file
[i
];
345 /* Always compare file1 to file2, even if file2 is "-".
346 This is needed for -mAeExX3. Using the file0 as
347 the common file would produce wrong results, because if the
348 file0-file1 diffs didn't line up with the file0-file2 diffs
349 (which is entirely possible since we don't use diff's -n option),
350 diff3 might report phantom changes from file1 to file2.
352 Also, try to compare file0 to file1, because this is where
353 changes are expected to come from. Diffing between these pairs
354 of files is more likely to avoid phantom changes from file0 to file1.
356 Historically, the default common file was file2, so some older
357 applications (e.g. Emacs ediff) used file2 as the ancestor. So,
358 for compatibility, if this is a 3-way diff (not a merge or
359 edscript), prefer file2 as the common file. */
361 common
= 2 - (edscript
| merge
);
363 if (strcmp (file
[common
], "-") == 0)
365 /* Sigh. We've got standard input as the common file. We can't
366 call diff twice on stdin. Use the other arg as the common
369 if (strcmp (file
[0], "-") == 0 || strcmp (file
[common
], "-") == 0)
370 fatal ("`-' specified for more than one input file");
374 mapping
[1] = 3 - common
;
377 for (i
= 0; i
< 3; i
++)
378 rev_mapping
[mapping
[i
]] = i
;
380 for (i
= 0; i
< 3; i
++)
381 if (strcmp (file
[i
], "-") != 0)
383 if (stat (file
[i
], &statb
) < 0)
384 perror_with_exit (file
[i
]);
385 else if (S_ISDIR (statb
.st_mode
))
386 error (EXIT_TROUBLE
, EISDIR
, "%s", file
[i
]);
390 /* System V fork+wait does not work if SIGCHLD is ignored. */
391 signal (SIGCHLD
, SIG_DFL
);
394 commonname
= file
[rev_mapping
[FILEC
]];
395 thread1
= process_diff (file
[rev_mapping
[FILE1
]], commonname
, &last_block
);
396 thread0
= process_diff (file
[rev_mapping
[FILE0
]], commonname
, &last_block
);
397 diff3
= make_3way_diff (thread0
, thread1
);
400 = output_diff3_edscript (stdout
, diff3
, mapping
, rev_mapping
,
401 tag_strings
[0], tag_strings
[1], tag_strings
[2]);
404 if (! freopen (file
[rev_mapping
[FILE0
]], "r", stdin
))
405 perror_with_exit (file
[rev_mapping
[FILE0
]]);
407 = output_diff3_merge (stdin
, stdout
, diff3
, mapping
, rev_mapping
,
408 tag_strings
[0], tag_strings
[1], tag_strings
[2]);
410 fatal ("read failed");
414 output_diff3 (stdout
, diff3
, mapping
, rev_mapping
);
419 exit (conflicts_found
);
420 return conflicts_found
;
424 try_help (char const *reason_msgid
, char const *operand
)
427 error (0, 0, _(reason_msgid
), operand
);
428 error (EXIT_TROUBLE
, 0,
429 _("Try `%s --help' for more information."), program_name
);
437 fatal ("write failed");
438 else if (fclose (stdout
) != 0)
439 perror_with_exit (_("standard output"));
442 static char const * const option_help_msgid
[] = {
443 N_("-e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE."),
444 N_("-E --show-overlap Output unmerged changes, bracketing conflicts."),
445 N_("-A --show-all Output all changes, bracketing conflicts."),
446 N_("-x --overlap-only Output overlapping changes."),
447 N_("-X Output overlapping changes, bracketing them."),
448 N_("-3 --easy-only Output unmerged nonoverlapping changes."),
450 N_("-m --merge Output merged file instead of ed script (default -A)."),
451 N_("-L LABEL --label=LABEL Use LABEL instead of file name."),
452 N_("-i Append `w' and `q' commands to ed scripts."),
453 N_("-a --text Treat all files as text."),
454 N_("-T --initial-tab Make tabs line up by prepending a tab."),
455 N_("--diff-program=PROGRAM Use PROGRAM to compare files."),
457 N_("-v --version Output version info."),
458 N_("--help Output this help."),
465 char const * const *p
;
467 printf (_("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n"),
469 printf ("%s\n\n", _("Compare three files line by line."));
470 for (p
= option_help_msgid
; *p
; p
++)
472 printf (" %s\n", _(*p
));
475 printf ("\n%s\n\n%s\n",
476 _("If a FILE is `-', read standard input."),
477 _("Report bugs to <bug-gnu-utils@gnu.org>."));
481 * Routines that combine the two diffs together into one. The
482 * algorithm used follows:
484 * File2 is shared in common between the two diffs.
485 * Diff02 is the diff between 0 and 2.
486 * Diff12 is the diff between 1 and 2.
488 * 1) Find the range for the first block in File2.
489 * a) Take the lowest of the two ranges (in File2) in the two
490 * current blocks (one from each diff) as being the low
491 * water mark. Assign the upper end of this block as
492 * being the high water mark and move the current block up
493 * one. Mark the block just moved over as to be used.
494 * b) Check the next block in the diff that the high water
495 * mark is *not* from.
497 * *If* the high water mark is above
498 * the low end of the range in that block,
500 * mark that block as to be used and move the current
501 * block up. Set the high water mark to the max of
502 * the high end of this block and the current. Repeat b.
504 * 2) Find the corresponding ranges in File0 (from the blocks
505 * in diff02; line per line outside of diffs) and in File1.
506 * Create a diff3_block, reserving space as indicated by the ranges.
508 * 3) Copy all of the pointers for file2 in. At least for now,
509 * do memcmp's between corresponding strings in the two diffs.
511 * 4) Copy all of the pointers for file0 and 1 in. Get what you
512 * need from file2 (when there isn't a diff block, it's
513 * identical to file2 within the range between diff blocks).
515 * 5) If the diff blocks you used came from only one of the two
516 * strings of diffs, then that file (i.e. the one other than
517 * the common file in that diff) is the odd person out. If you used
518 * diff blocks from both sets, check to see if files 0 and 1 match:
520 * Same number of lines? If so, do a set of memcmp's (if a
521 * memcmp matches; copy the pointer over; it'll be easier later
522 * if you have to do any compares). If they match, 0 & 1 are
523 * the same. If not, all three different.
525 * Then you do it again, until you run out of blocks.
530 * This routine makes a three way diff (chain of diff3_block's) from two
531 * two way diffs (chains of diff_block's). It is assumed that each of
532 * the two diffs passed are onto the same file (i.e. that each of the
533 * diffs were made "to" the same file). The three way diff pointer
534 * returned will have numbering FILE0--the other file in diff02,
535 * FILE1--the other file in diff12, and FILEC--the common file.
537 static struct diff3_block
*
538 make_3way_diff (struct diff_block
*thread0
, struct diff_block
*thread1
)
541 * This routine works on the two diffs passed to it as threads.
542 * Thread number 0 is diff02, thread number 1 is diff12. The USING
543 * array is set to the base of the list of blocks to be used to
544 * construct each block of the three way diff; if no blocks from a
545 * particular thread are to be used, that element of the using array
546 * is set to 0. The elements LAST_USING array are set to the last
547 * elements on each of the using lists.
549 * The HIGH_WATER_MARK is set to the highest line number in the common file
550 * described in any of the diffs in either of the USING lists. The
551 * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK
552 * and BASE_WATER_THREAD describe the lowest line number in the common file
553 * described in any of the diffs in either of the USING lists. The
554 * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
557 * The HIGH_WATER_DIFF should always be equal to LAST_USING
558 * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for
559 * higher water, and should always be equal to
560 * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread
561 * in which the OTHER_DIFF is, and hence should always be equal to
562 * HIGH_WATER_THREAD ^ 0x1.
564 * The variable LAST_DIFF is kept set to the last diff block produced
565 * by this routine, for line correspondence purposes between that diff
566 * and the one currently being worked on. It is initialized to
567 * ZERO_DIFF before any blocks have been created.
570 struct diff_block
*using[2];
571 struct diff_block
*last_using
[2];
572 struct diff_block
*current
[2];
576 int high_water_thread
;
577 int base_water_thread
;
580 struct diff_block
*high_water_diff
;
581 struct diff_block
*other_diff
;
583 struct diff3_block
*result
;
584 struct diff3_block
*tmpblock
;
585 struct diff3_block
**result_end
;
587 struct diff3_block
const *last_diff3
;
589 static struct diff3_block
const zero_diff3
;
593 result_end
= &result
;
594 current
[0] = thread0
; current
[1] = thread1
;
595 last_diff3
= &zero_diff3
;
597 /* Sniff up the threads until we reach the end */
599 while (current
[0] || current
[1])
601 using[0] = using[1] = last_using
[0] = last_using
[1] = 0;
603 /* Setup low and high water threads, diffs, and marks. */
605 base_water_thread
= 1;
606 else if (!current
[1])
607 base_water_thread
= 0;
610 (D_LOWLINE (current
[0], FC
) > D_LOWLINE (current
[1], FC
));
612 high_water_thread
= base_water_thread
;
614 high_water_diff
= current
[high_water_thread
];
616 high_water_mark
= D_HIGHLINE (high_water_diff
, FC
);
618 /* Make the diff you just got info from into the using class */
619 using[high_water_thread
]
620 = last_using
[high_water_thread
]
622 current
[high_water_thread
] = high_water_diff
->next
;
623 last_using
[high_water_thread
]->next
= 0;
625 /* And mark the other diff */
626 other_thread
= high_water_thread
^ 0x1;
627 other_diff
= current
[other_thread
];
629 /* Shuffle up the ladder, checking the other diff to see if it
630 needs to be incorporated. */
632 && D_LOWLINE (other_diff
, FC
) <= high_water_mark
+ 1)
635 /* Incorporate this diff into the using list. Note that
636 this doesn't take it off the current list */
637 if (using[other_thread
])
638 last_using
[other_thread
]->next
= other_diff
;
640 using[other_thread
] = other_diff
;
641 last_using
[other_thread
] = other_diff
;
643 /* Take it off the current list. Note that this following
644 code assumes that other_diff enters it equal to
645 current[high_water_thread ^ 0x1] */
646 current
[other_thread
] = current
[other_thread
]->next
;
647 other_diff
->next
= 0;
649 /* Set the high_water stuff
650 If this comparison is equal, then this is the last pass
651 through this loop; since diff blocks within a given
652 thread cannot overlap, the high_water_mark will be
653 *below* the range_start of either of the next diffs. */
655 if (high_water_mark
< D_HIGHLINE (other_diff
, FC
))
657 high_water_thread
^= 1;
658 high_water_diff
= other_diff
;
659 high_water_mark
= D_HIGHLINE (other_diff
, FC
);
662 /* Set the other diff */
663 other_thread
= high_water_thread
^ 0x1;
664 other_diff
= current
[other_thread
];
667 /* The using lists contain a list of all of the blocks to be
668 included in this diff3_block. Create it. */
670 tmpblock
= using_to_diff3_block (using, last_using
,
671 base_water_thread
, high_water_thread
,
675 fatal ("internal error: screwup in format of diff blocks");
677 /* Put it on the list. */
678 *result_end
= tmpblock
;
679 result_end
= &tmpblock
->next
;
681 /* Set up corresponding lines correctly. */
682 last_diff3
= tmpblock
;
688 * using_to_diff3_block:
689 * This routine takes two lists of blocks (from two separate diff
690 * threads) and puts them together into one diff3 block.
691 * It then returns a pointer to this diff3 block or 0 for failure.
693 * All arguments besides using are for the convenience of the routine;
694 * they could be derived from the using array.
695 * LAST_USING is a pair of pointers to the last blocks in the using
697 * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
698 * and highest line numbers for File0.
699 * last_diff3 contains the last diff produced in the calling routine.
700 * This is used for lines mappings which would still be identical to
701 * the state that diff ended in.
703 * A distinction should be made in this routine between the two diffs
704 * that are part of a normal two diff block, and the three diffs that
705 * are part of a diff3_block.
707 static struct diff3_block
*
708 using_to_diff3_block (struct diff_block
*using[2],
709 struct diff_block
*last_using
[2],
710 int low_thread
, int high_thread
,
711 struct diff3_block
const *last_diff3
)
714 struct diff3_block
*result
;
715 struct diff_block
*ptr
;
719 /* Find the range in the common file. */
720 lin lowc
= D_LOWLINE (using[low_thread
], FC
);
721 lin highc
= D_HIGHLINE (last_using
[high_thread
], FC
);
723 /* Find the ranges in the other files.
724 If using[d] is null, that means that the file to which that diff
725 refers is equivalent to the common file over this range. */
727 for (d
= 0; d
< 2; d
++)
730 low
[d
] = D_LOW_MAPLINE (using[d
], FC
, FO
, lowc
);
731 high
[d
] = D_HIGH_MAPLINE (last_using
[d
], FC
, FO
, highc
);
735 low
[d
] = D_HIGH_MAPLINE (last_diff3
, FILEC
, FILE0
+ d
, lowc
);
736 high
[d
] = D_HIGH_MAPLINE (last_diff3
, FILEC
, FILE0
+ d
, highc
);
739 /* Create a block with the appropriate sizes */
740 result
= create_diff3_block (low
[0], high
[0], low
[1], high
[1], lowc
, highc
);
742 /* Copy information for the common file.
743 Return with a zero if any of the compares failed. */
745 for (d
= 0; d
< 2; d
++)
746 for (ptr
= using[d
]; ptr
; ptr
= D_NEXT (ptr
))
748 lin result_offset
= D_LOWLINE (ptr
, FC
) - lowc
;
750 if (!copy_stringlist (D_LINEARRAY (ptr
, FC
),
751 D_LENARRAY (ptr
, FC
),
752 D_LINEARRAY (result
, FILEC
) + result_offset
,
753 D_LENARRAY (result
, FILEC
) + result_offset
,
754 D_NUMLINES (ptr
, FC
)))
758 /* Copy information for file d. First deal with anything that might be
759 before the first diff. */
761 for (d
= 0; d
< 2; d
++)
763 struct diff_block
*u
= using[d
];
764 lin lo
= low
[d
], hi
= high
[d
];
767 i
+ lo
< (u
? D_LOWLINE (u
, FO
) : hi
+ 1);
770 D_RELNUM (result
, FILE0
+ d
, i
) = D_RELNUM (result
, FILEC
, i
);
771 D_RELLEN (result
, FILE0
+ d
, i
) = D_RELLEN (result
, FILEC
, i
);
774 for (ptr
= u
; ptr
; ptr
= D_NEXT (ptr
))
776 lin result_offset
= D_LOWLINE (ptr
, FO
) - lo
;
779 if (!copy_stringlist (D_LINEARRAY (ptr
, FO
),
780 D_LENARRAY (ptr
, FO
),
781 D_LINEARRAY (result
, FILE0
+ d
) + result_offset
,
782 D_LENARRAY (result
, FILE0
+ d
) + result_offset
,
783 D_NUMLINES (ptr
, FO
)))
786 /* Catch the lines between here and the next diff */
787 linec
= D_HIGHLINE (ptr
, FC
) + 1 - lowc
;
788 for (i
= D_HIGHLINE (ptr
, FO
) + 1 - lo
;
789 i
< (D_NEXT (ptr
) ? D_LOWLINE (D_NEXT (ptr
), FO
) : hi
+ 1) - lo
;
792 D_RELNUM (result
, FILE0
+ d
, i
) = D_RELNUM (result
, FILEC
, linec
);
793 D_RELLEN (result
, FILE0
+ d
, i
) = D_RELLEN (result
, FILEC
, linec
);
801 D3_TYPE (result
) = DIFF_2ND
;
803 D3_TYPE (result
) = DIFF_1ST
;
806 lin nl0
= D_NUMLINES (result
, FILE0
);
807 lin nl1
= D_NUMLINES (result
, FILE1
);
810 || !compare_line_list (D_LINEARRAY (result
, FILE0
),
811 D_LENARRAY (result
, FILE0
),
812 D_LINEARRAY (result
, FILE1
),
813 D_LENARRAY (result
, FILE1
),
815 D3_TYPE (result
) = DIFF_ALL
;
817 D3_TYPE (result
) = DIFF_3RD
;
824 * This routine copies pointers from a list of strings to a different list
825 * of strings. If a spot in the second list is already filled, it
826 * makes sure that it is filled with the same string; if not it
827 * returns 0, the copy incomplete.
828 * Upon successful completion of the copy, it returns 1.
831 copy_stringlist (char * const fromptrs
[], size_t const fromlengths
[],
832 char *toptrs
[], size_t tolengths
[],
835 register char * const *f
= fromptrs
;
836 register char **t
= toptrs
;
837 register size_t const *fl
= fromlengths
;
838 register size_t *tl
= tolengths
;
843 { if (*fl
!= *tl
|| memcmp (*f
, *t
, *fl
)) return 0; }
845 { *t
= *f
; *tl
= *fl
; }
847 t
++; f
++; tl
++; fl
++;
853 * Create a diff3_block, with ranges as specified in the arguments.
854 * Allocate the arrays for the various pointers (and zero them) based
855 * on the arguments passed. Return the block as a result.
857 static struct diff3_block
*
858 create_diff3_block (lin low0
, lin high0
,
862 struct diff3_block
*result
= xmalloc (sizeof *result
);
865 D3_TYPE (result
) = ERROR
;
869 D_LOWLINE (result
, FILE0
) = low0
;
870 D_HIGHLINE (result
, FILE0
) = high0
;
871 D_LOWLINE (result
, FILE1
) = low1
;
872 D_HIGHLINE (result
, FILE1
) = high1
;
873 D_LOWLINE (result
, FILE2
) = low2
;
874 D_HIGHLINE (result
, FILE2
) = high2
;
876 /* Allocate and zero space */
877 numlines
= D_NUMLINES (result
, FILE0
);
880 D_LINEARRAY (result
, FILE0
) = xcalloc (numlines
, sizeof (char *));
881 D_LENARRAY (result
, FILE0
) = xcalloc (numlines
, sizeof (size_t));
885 D_LINEARRAY (result
, FILE0
) = 0;
886 D_LENARRAY (result
, FILE0
) = 0;
889 numlines
= D_NUMLINES (result
, FILE1
);
892 D_LINEARRAY (result
, FILE1
) = xcalloc (numlines
, sizeof (char *));
893 D_LENARRAY (result
, FILE1
) = xcalloc (numlines
, sizeof (size_t));
897 D_LINEARRAY (result
, FILE1
) = 0;
898 D_LENARRAY (result
, FILE1
) = 0;
901 numlines
= D_NUMLINES (result
, FILE2
);
904 D_LINEARRAY (result
, FILE2
) = xcalloc (numlines
, sizeof (char *));
905 D_LENARRAY (result
, FILE2
) = xcalloc (numlines
, sizeof (size_t));
909 D_LINEARRAY (result
, FILE2
) = 0;
910 D_LENARRAY (result
, FILE2
) = 0;
918 * Compare two lists of lines of text.
919 * Return 1 if they are equivalent, 0 if not.
922 compare_line_list (char * const list1
[], size_t const lengths1
[],
923 char * const list2
[], size_t const lengths2
[],
934 if (!*l1
|| !*l2
|| *lgths1
!= *lgths2
++
935 || memcmp (*l1
++, *l2
++, *lgths1
++))
941 * Routines to input and parse two way diffs.
944 static struct diff_block
*
945 process_diff (char const *filea
,
947 struct diff_block
**last_block
)
954 struct diff_block
*block_list
, **block_list_end
, *bptr
;
955 size_t too_many_lines
= (PTRDIFF_MAX
956 / MIN (sizeof *bptr
->lines
[1],
957 sizeof *bptr
->lengths
[1]));
959 diff_limit
= read_diff (filea
, fileb
, &diff_contents
);
960 scan_diff
= diff_contents
;
961 block_list_end
= &block_list
;
962 bptr
= 0; /* Pacify `gcc -W'. */
964 while (scan_diff
< diff_limit
)
966 bptr
= xmalloc (sizeof *bptr
);
967 bptr
->lines
[0] = bptr
->lines
[1] = 0;
968 bptr
->lengths
[0] = bptr
->lengths
[1] = 0;
970 dt
= process_diff_control (&scan_diff
, bptr
);
971 if (dt
== ERROR
|| *scan_diff
!= '\n')
973 fprintf (stderr
, _("%s: diff failed: "), program_name
);
976 putc (*scan_diff
, stderr
);
978 while (*scan_diff
++ != '\n');
983 /* Force appropriate ranges to be null, if necessary */
987 bptr
->ranges
[0][0]++;
990 bptr
->ranges
[1][0]++;
995 fatal ("internal error: invalid diff type in process_diff");
999 /* Allocate space for the pointers for the lines from filea, and
1000 parcel them out among these pointers */
1003 lin numlines
= D_NUMLINES (bptr
, 0);
1004 if (too_many_lines
<= numlines
)
1006 bptr
->lines
[0] = xmalloc (numlines
* sizeof *bptr
->lines
[0]);
1007 bptr
->lengths
[0] = xmalloc (numlines
* sizeof *bptr
->lengths
[0]);
1008 for (i
= 0; i
< numlines
; i
++)
1009 scan_diff
= scan_diff_line (scan_diff
,
1010 &(bptr
->lines
[0][i
]),
1011 &(bptr
->lengths
[0][i
]),
1016 /* Get past the separator for changes */
1019 if (strncmp (scan_diff
, "---\n", 4))
1020 fatal ("invalid diff format; invalid change separator");
1024 /* Allocate space for the pointers for the lines from fileb, and
1025 parcel them out among these pointers */
1028 lin numlines
= D_NUMLINES (bptr
, 1);
1029 if (too_many_lines
<= numlines
)
1031 bptr
->lines
[1] = xmalloc (numlines
* sizeof *bptr
->lines
[1]);
1032 bptr
->lengths
[1] = xmalloc (numlines
* sizeof *bptr
->lengths
[1]);
1033 for (i
= 0; i
< numlines
; i
++)
1034 scan_diff
= scan_diff_line (scan_diff
,
1035 &(bptr
->lines
[1][i
]),
1036 &(bptr
->lengths
[1][i
]),
1041 /* Place this block on the blocklist. */
1042 *block_list_end
= bptr
;
1043 block_list_end
= &bptr
->next
;
1046 *block_list_end
= 0;
1052 * This routine will parse a normal format diff control string. It
1053 * returns the type of the diff (ERROR if the format is bad). All of
1054 * the other important information is filled into to the structure
1055 * pointed to by db, and the string pointer (whose location is passed
1056 * to this routine) is updated to point beyond the end of the string
1057 * parsed. Note that only the ranges in the diff_block will be set by
1060 * If some specific pair of numbers has been reduced to a single
1061 * number, then both corresponding numbers in the diff block are set
1062 * to that number. In general these numbers are interpreted as ranges
1063 * inclusive, unless being used by the ADD or DELETE commands. It is
1064 * assumed that these will be special cased in a superior routine.
1067 static enum diff_type
1068 process_diff_control (char **string
, struct diff_block
*db
)
1072 enum diff_type type
;
1074 /* These macros are defined here because they can use variables
1075 defined in this function. Don't try this at home kids, we're
1076 trained professionals!
1078 Also note that SKIPWHITE only recognizes tabs and spaces, and
1079 that READNUM can only read positive, integral numbers */
1081 #define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; }
1082 #define READNUM(s, num) \
1083 { unsigned char c = *s; if (!ISDIGIT (c)) return ERROR; holdnum = 0; \
1084 do { holdnum = (c - '0' + holdnum * 10); } \
1085 while (ISDIGIT (c = *++s)); (num) = holdnum; }
1087 /* Read first set of digits */
1089 READNUM (s
, db
->ranges
[0][RANGE_START
]);
1091 /* Was that the only digit? */
1095 /* Get the next digit */
1097 READNUM (s
, db
->ranges
[0][RANGE_END
]);
1100 db
->ranges
[0][RANGE_END
] = db
->ranges
[0][RANGE_START
];
1102 /* Get the letter */
1116 return ERROR
; /* Bad format */
1118 s
++; /* Past letter */
1120 /* Read second set of digits */
1122 READNUM (s
, db
->ranges
[1][RANGE_START
]);
1124 /* Was that the only digit? */
1128 /* Get the next digit */
1130 READNUM (s
, db
->ranges
[1][RANGE_END
]);
1131 SKIPWHITE (s
); /* To move to end */
1134 db
->ranges
[1][RANGE_END
] = db
->ranges
[1][RANGE_START
];
1141 read_diff (char const *filea
,
1143 char **output_placement
)
1146 size_t current_chunk_size
, total
;
1149 struct stat pipestat
;
1151 #if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
1153 char const *argv
[8];
1159 *ap
++ = diff_program
;
1162 *ap
++ = "--horizon-lines=100";
1168 if (pipe (fds
) != 0)
1169 perror_with_exit ("pipe");
1176 if (fds
[1] != STDOUT_FILENO
)
1178 dup2 (fds
[1], STDOUT_FILENO
);
1182 /* The cast to (char **) is needed for portability to older
1183 hosts with a nonstandard prototype for execvp. */
1184 execvp (diff_program
, (char **) argv
);
1186 _exit (errno
== ENOEXEC
? 126 : 127);
1190 perror_with_exit ("fork");
1192 close (fds
[1]); /* Prevent erroneous lack of EOF */
1198 char const args
[] = " -a --horizon-lines=100 -- ";
1199 char *command
= xmalloc (quote_system_arg (0, diff_program
)
1201 + quote_system_arg (0, filea
) + 1
1202 + quote_system_arg (0, fileb
) + 1);
1204 p
+= quote_system_arg (p
, diff_program
);
1205 strcpy (p
, args
+ (text
? 0 : 3));
1207 p
+= quote_system_arg (p
, filea
);
1209 p
+= quote_system_arg (p
, fileb
);
1212 fpipe
= popen (command
, "r");
1214 perror_with_exit (command
);
1216 fd
= fileno (fpipe
);
1220 if (fstat (fd
, &pipestat
) != 0)
1221 perror_with_exit ("fstat");
1222 current_chunk_size
= MAX (1, STAT_BLOCKSIZE (pipestat
));
1223 diff_result
= xmalloc (current_chunk_size
);
1228 size_t bytes_to_read
= current_chunk_size
- total
;
1229 size_t bytes
= block_read (fd
, diff_result
+ total
, bytes_to_read
);
1231 if (bytes
!= bytes_to_read
)
1233 if (bytes
== SIZE_MAX
)
1234 perror_with_exit (_("read failed"));
1237 if (PTRDIFF_MAX
/ 2 <= current_chunk_size
)
1239 current_chunk_size
*= 2;
1240 diff_result
= xrealloc (diff_result
, current_chunk_size
);
1243 if (total
!= 0 && diff_result
[total
-1] != '\n')
1244 fatal ("invalid diff format; incomplete last line");
1246 *output_placement
= diff_result
;
1248 #if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
1250 wstatus
= pclose (fpipe
);
1256 if (close (fd
) != 0)
1257 perror_with_exit ("close");
1258 if (waitpid (pid
, &wstatus
, 0) < 0)
1259 perror_with_exit ("waitpid");
1263 if (! werrno
&& WIFEXITED (wstatus
))
1264 switch (WEXITSTATUS (wstatus
))
1267 error (EXIT_TROUBLE
, 0, _("subsidiary program `%s' not executable"),
1270 error (EXIT_TROUBLE
, 0, _("subsidiary program `%s' not found"),
1273 if (werrno
|| ! (WIFEXITED (wstatus
) && WEXITSTATUS (wstatus
) < 2))
1274 error (EXIT_TROUBLE
, werrno
, _("subsidiary program `%s' failed"),
1277 return diff_result
+ total
;
1282 * Scan a regular diff line (consisting of > or <, followed by a
1283 * space, followed by text (including nulls) up to a newline.
1285 * This next routine began life as a macro and many parameters in it
1286 * are used as call-by-reference values.
1289 scan_diff_line (char *scan_ptr
, char **set_start
, size_t *set_length
,
1290 char *limit
, char leadingchar
)
1294 if (!(scan_ptr
[0] == leadingchar
1295 && scan_ptr
[1] == ' '))
1296 fatal ("invalid diff format; incorrect leading line chars");
1298 *set_start
= line_ptr
= scan_ptr
+ 2;
1299 while (*line_ptr
++ != '\n')
1302 /* Include newline if the original line ended in a newline,
1303 or if an edit script is being generated.
1304 Copy any missing newline message to stderr if an edit script is being
1305 generated, because edit scripts cannot handle missing newlines.
1306 Return the beginning of the next line. */
1307 *set_length
= line_ptr
- *set_start
;
1308 if (line_ptr
< limit
&& *line_ptr
== '\\')
1311 fprintf (stderr
, "%s:", program_name
);
1318 putc (*line_ptr
, stderr
);
1320 while (*line_ptr
++ != '\n');
1327 * This routine outputs a three way diff passed as a list of
1329 * The argument MAPPING is indexed by external file number (in the
1330 * argument list) and contains the internal file number (from the
1331 * diff passed). This is important because the user expects his
1332 * outputs in terms of the argument list number, and the diff passed
1333 * may have been done slightly differently (if the last argument
1334 * was "-", for example).
1335 * REV_MAPPING is the inverse of MAPPING.
1338 output_diff3 (FILE *outputfile
, struct diff3_block
*diff
,
1339 int const mapping
[3], int const rev_mapping
[3])
1344 struct diff3_block
*ptr
;
1348 static int skew_increment
[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
1349 char const *line_prefix
= initial_tab
? "\t" : " ";
1351 for (ptr
= diff
; ptr
; ptr
= D_NEXT (ptr
))
1355 switch (ptr
->correspond
)
1359 dontprint
= 3; /* Print them all */
1360 oddoneout
= 3; /* Nobody's odder than anyone else */
1365 oddoneout
= rev_mapping
[ptr
->correspond
- DIFF_1ST
];
1367 x
[0] = oddoneout
+ '1';
1369 dontprint
= oddoneout
== 0;
1372 fatal ("internal error: invalid diff type passed to output");
1374 fprintf (outputfile
, "====%s\n", x
);
1376 /* Go 0, 2, 1 if the first and third outputs are equivalent. */
1378 i
= (oddoneout
== 1 ? skew_increment
[i
] : i
+ 1))
1380 int realfile
= mapping
[i
];
1381 lin lowt
= D_LOWLINE (ptr
, realfile
);
1382 lin hight
= D_HIGHLINE (ptr
, realfile
);
1384 long lhight
= hight
;
1386 fprintf (outputfile
, "%d:", i
+ 1);
1387 switch (lowt
- hight
)
1390 fprintf (outputfile
, "%lda\n", llowt
- 1);
1393 fprintf (outputfile
, "%ldc\n", llowt
);
1396 fprintf (outputfile
, "%ld,%ldc\n", llowt
, lhight
);
1400 if (i
== dontprint
) continue;
1407 fprintf (outputfile
, line_prefix
);
1408 cp
= D_RELNUM (ptr
, realfile
, line
);
1409 length
= D_RELLEN (ptr
, realfile
, line
);
1410 fwrite (cp
, sizeof (char), length
, outputfile
);
1412 while (++line
< hight
- lowt
+ 1);
1413 if (cp
[length
- 1] != '\n')
1414 fprintf (outputfile
, "\n\\ %s\n",
1415 _("No newline at end of file"));
1423 * Output to OUTPUTFILE the lines of B taken from FILENUM.
1424 * Double any initial '.'s; yield nonzero if any initial '.'s were doubled.
1427 dotlines (FILE *outputfile
, struct diff3_block
*b
, int filenum
)
1430 bool leading_dot
= 0;
1433 i
< D_NUMLINES (b
, filenum
);
1436 char *line
= D_RELNUM (b
, filenum
, i
);
1440 fprintf (outputfile
, ".");
1442 fwrite (line
, sizeof (char),
1443 D_RELLEN (b
, filenum
, i
), outputfile
);
1450 * Output to OUTPUTFILE a '.' line. If LEADING_DOT is nonzero,
1451 * also output a command that removes initial '.'s
1452 * starting with line START and continuing for NUM lines.
1453 * (START is long, not lin, for convenience with printf %ld formats.)
1456 undotlines (FILE *outputfile
, bool leading_dot
, long start
, lin num
)
1458 fprintf (outputfile
, ".\n");
1462 fprintf (outputfile
, "%lds/^\\.//\n", start
);
1464 fprintf (outputfile
, "%ld,%lds/^\\.//\n", start
, start
+ num
- 1);
1469 * This routine outputs a diff3 set of blocks as an ed script. This
1470 * script applies the changes between file's 2 & 3 to file 1. It
1471 * takes the precise format of the ed script to be output from global
1472 * variables set during options processing. Note that it does
1473 * destructive things to the set of diff3 blocks it is passed; it
1474 * reverses their order (this gets around the problems involved with
1475 * changing line numbers in an ed script).
1477 * Note that this routine has the same problem of mapping as the last
1478 * one did; the variable MAPPING maps from file number according to
1479 * the argument list to file number according to the diff passed. All
1480 * files listed below are in terms of the argument list.
1481 * REV_MAPPING is the inverse of MAPPING.
1483 * The arguments FILE0, FILE1 and FILE2 are the strings to print
1484 * as the names of the three files. These may be the actual names,
1485 * or may be the arguments specified with -L.
1487 * Returns 1 if conflicts were found.
1491 output_diff3_edscript (FILE *outputfile
, struct diff3_block
*diff
,
1492 int const mapping
[3], int const rev_mapping
[3],
1493 char const *file0
, char const *file1
, char const *file2
)
1496 bool conflicts_found
= 0, conflict
;
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
]);
1509 /* If we aren't supposed to do this output block, skip it. */
1513 case DIFF_2ND
: if (!show_2nd
) continue; conflict
= 1; break;
1514 case DIFF_3RD
: if (overlap_only
) continue; conflict
= 0; 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
= 1;
1526 /* Mark end of conflict. */
1528 fprintf (outputfile
, "%lda\n", high0
);
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 fprintf (outputfile
, "=======\n");
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
);
1553 if (type
== DIFF_2ND
)
1555 /* Prepend lines from FILE1. */
1556 leading_dot
= dotlines (outputfile
, b
, mapping
[FILE1
]);
1557 fprintf (outputfile
, "=======\n");
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
]));
1590 if (finalwrite
) fprintf (outputfile
, "w\nq\n");
1591 return conflicts_found
;
1595 * Read from INFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF
1596 * as a merged file. This acts like 'ed file0 <[output_diff3_edscript]',
1597 * except that it works even for binary data or incomplete lines.
1599 * As before, MAPPING maps from arg list file number to diff file number,
1600 * REV_MAPPING is its inverse,
1601 * and FILE0, FILE1, and FILE2 are the names of the files.
1603 * Returns 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
= 0, conflict
;
1614 struct diff3_block
*b
;
1617 for (b
= diff
; b
; b
= b
->next
)
1619 /* Must do mapping correctly. */
1621 = ((b
->correspond
== DIFF_ALL
)
1623 : DIFF_1ST
+ rev_mapping
[b
->correspond
- DIFF_1ST
]);
1624 char const *format_2nd
= "<<<<<<< %s\n";
1626 /* If we aren't supposed to do this output block, skip it. */
1630 case DIFF_2ND
: if (!show_2nd
) continue; conflict
= 1; break;
1631 case DIFF_3RD
: if (overlap_only
) continue; conflict
= 0; break;
1632 case DIFF_ALL
: if (simple_only
) continue; conflict
= flagging
;
1633 format_2nd
= "||||||| %s\n";
1637 /* Copy I lines from file 0. */
1638 i
= D_LOWLINE (b
, FILE0
) - linesread
- 1;
1646 if (ferror (infile
))
1647 perror_with_exit (_("read failed"));
1648 else if (feof (infile
))
1649 fatal ("input file shrank");
1651 putc (c
, outputfile
);
1657 conflicts_found
= 1;
1659 if (type
== DIFF_ALL
)
1661 /* Put in lines from FILE0 with bracket. */
1662 fprintf (outputfile
, "<<<<<<< %s\n", file0
);
1664 i
< D_NUMLINES (b
, mapping
[FILE0
]);
1666 fwrite (D_RELNUM (b
, mapping
[FILE0
], i
), sizeof (char),
1667 D_RELLEN (b
, mapping
[FILE0
], i
), outputfile
);
1672 /* Put in lines from FILE1 with bracket. */
1673 fprintf (outputfile
, format_2nd
, file1
);
1675 i
< D_NUMLINES (b
, mapping
[FILE1
]);
1677 fwrite (D_RELNUM (b
, mapping
[FILE1
], i
), sizeof (char),
1678 D_RELLEN (b
, mapping
[FILE1
], i
), outputfile
);
1681 fprintf (outputfile
, "=======\n");
1684 /* Put in lines from FILE2. */
1686 i
< D_NUMLINES (b
, mapping
[FILE2
]);
1688 fwrite (D_RELNUM (b
, mapping
[FILE2
], i
), sizeof (char),
1689 D_RELLEN (b
, mapping
[FILE2
], i
), outputfile
);
1692 fprintf (outputfile
, ">>>>>>> %s\n", file2
);
1694 /* Skip I lines in file 0. */
1695 i
= D_NUMLINES (b
, FILE0
);
1698 while ((c
= getc (infile
)) != '\n')
1701 if (ferror (infile
))
1702 perror_with_exit (_("read failed"));
1703 else if (feof (infile
))
1706 fatal ("input file shrank");
1707 return conflicts_found
;
1711 /* Copy rest of common file. */
1712 while ((c
= getc (infile
)) != EOF
|| !(ferror (infile
) | feof (infile
)))
1713 putc (c
, outputfile
);
1714 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
);