1 /* Three way file comparison program (diff3) for Project GNU.
2 Copyright (C) 1988, 1989, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
19 /* Written by Randy Smith */
20 /* Librarification by Tim Pierce */
28 /* diff3.c has a real initialize_main function. */
29 #ifdef initialize_main
30 #undef initialize_main
33 extern char const diff_version_string[];
37 extern const struct diff_callbacks *callbacks;
39 void write_output PARAMS((char const *, size_t));
40 void printf_output PARAMS((char const *, ...))
41 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6)
42 __attribute__ ((__format__ (__printf__, 1, 2)))
45 void flush_output PARAMS((void));
47 char * cvs_temp_name PARAMS((void));
50 * Internal data structures and macros for the diff3 program; includes
51 * data structures for both diff3 diffs and normal diffs.
54 /* Different files within a three way diff. */
60 * A three way diff is built from two two-way diffs; the file which
61 * the two two-way diffs share is:
66 * Different files within a two way diff.
67 * FC is the common file, FO the other file.
72 /* The ranges are indexed by */
77 ERROR, /* Should not be used */
78 ADD, /* Two way diff add */
79 CHANGE, /* Two way diff change */
80 DELETE, /* Two way diff delete */
81 DIFF_ALL, /* All three are different */
82 DIFF_1ST, /* Only the first is different */
83 DIFF_2ND, /* Only the second */
84 DIFF_3RD /* Only the third */
89 int ranges[2][2]; /* Ranges are inclusive */
90 char **lines[2]; /* The actual lines (may contain nulls) */
91 size_t *lengths[2]; /* Line lengths (including newlines, if any) */
92 struct diff_block *next;
98 enum diff_type correspond; /* Type of diff */
99 int ranges[3][2]; /* Ranges are inclusive */
100 char **lines[3]; /* The actual lines (may contain nulls) */
101 size_t *lengths[3]; /* Line lengths (including newlines, if any) */
102 struct diff3_block *next;
106 * Access the ranges on a diff block.
108 #define D_LOWLINE(diff, filenum) \
109 ((diff)->ranges[filenum][START])
110 #define D_HIGHLINE(diff, filenum) \
111 ((diff)->ranges[filenum][END])
112 #define D_NUMLINES(diff, filenum) \
113 (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
116 * Access the line numbers in a file in a diff by relative line
117 * numbers (i.e. line number within the diff itself). Note that these
118 * are lvalues and can be used for assignment.
120 #define D_RELNUM(diff, filenum, linenum) \
121 ((diff)->lines[filenum][linenum])
122 #define D_RELLEN(diff, filenum, linenum) \
123 ((diff)->lengths[filenum][linenum])
126 * And get at them directly, when that should be necessary.
128 #define D_LINEARRAY(diff, filenum) \
129 ((diff)->lines[filenum])
130 #define D_LENARRAY(diff, filenum) \
131 ((diff)->lengths[filenum])
136 #define D_NEXT(diff) ((diff)->next)
139 * Access the type of a diff3 block.
141 #define D3_TYPE(diff) ((diff)->correspond)
144 * Line mappings based on diffs. The first maps off the top of the
145 * diff, the second off of the bottom.
147 #define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \
149 - D_HIGHLINE ((diff), (fromfile)) \
150 + D_HIGHLINE ((diff), (tofile)))
152 #define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \
154 - D_LOWLINE ((diff), (fromfile)) \
155 + D_LOWLINE ((diff), (tofile)))
158 * General memory allocation function.
160 #define ALLOCATE(number, type) \
161 (type *) xmalloc ((number) * sizeof (type))
163 /* Options variables for flags set on command line. */
165 /* If nonzero, treat all files as text files, never as binary. */
166 static int always_text;
168 /* If nonzero, write out an ed script instead of the standard diff3 format. */
171 /* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
172 preserve the lines which would normally be deleted from
173 file 1 with a special flagging mechanism. */
176 /* Number of lines to keep in identical prefix and suffix. */
177 static int const horizon_lines = 10;
179 /* Use a tab to align output lines (-T). */
180 static int tab_align_flag;
182 /* If nonzero, do not output information for overlapping diffs. */
183 static int simple_only;
185 /* If nonzero, do not output information for non-overlapping diffs. */
186 static int overlap_only;
188 /* If nonzero, show information for DIFF_2ND diffs. */
191 /* If nonzero, include `:wq' at the end of the script
192 to write out the file being edited. */
193 static int finalwrite;
195 /* If nonzero, output a merged file. */
198 extern char *diff_program_name;
200 static char *read_diff PARAMS((char const *, char const *, char **));
201 static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int));
202 static enum diff_type process_diff_control PARAMS((char **, struct diff_block *));
203 static int compare_line_list PARAMS((char * const[], size_t const[], char * const[], size_t const[], int));
204 static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int));
205 static int dotlines PARAMS((struct diff3_block *, int));
206 static int output_diff3_edscript PARAMS((struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));
207 static int output_diff3_merge PARAMS((FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));
208 static size_t myread PARAMS((int, char *, size_t));
209 static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int));
210 static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *));
211 static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *));
212 static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *));
213 static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **, char **));
214 static void check_output PARAMS((FILE *));
215 static void diff3_fatal PARAMS((char const *));
216 static void output_diff3 PARAMS((struct diff3_block *, int const[3], int const[3]));
217 static void diff3_perror_with_exit PARAMS((char const *));
218 static int try_help PARAMS((char const *));
219 static void undotlines PARAMS((int, int, int));
220 static void usage PARAMS((void));
221 static void initialize_main PARAMS((int *, char ***));
222 static void free_diff_blocks PARAMS((struct diff_block *));
223 static void free_diff3_blocks PARAMS((struct diff3_block *));
225 /* Functions provided in libdiff.a or other external sources. */
226 VOID *xmalloc PARAMS((size_t));
227 VOID *xrealloc PARAMS((VOID *, size_t));
228 void perror_with_name PARAMS((char const *));
229 void diff_error PARAMS((char const *, char const *, char const *));
231 /* Permit non-local exits from diff3. */
232 static jmp_buf diff3_abort_buf;
233 #define DIFF3_ABORT(retval) longjmp(diff3_abort_buf, retval)
235 static struct option const longopts[] =
238 {"show-all", 0, 0, 'A'},
240 {"show-overlap", 0, 0, 'E'},
241 {"label", 1, 0, 'L'},
242 {"merge", 0, 0, 'm'},
243 {"initial-tab", 0, 0, 'T'},
244 {"overlap-only", 0, 0, 'x'},
245 {"easy-only", 0, 0, '3'},
246 {"version", 0, 0, 'v'},
252 * Main program. Calls diff twice on two pairs of input files,
253 * combines the two diffs, and outputs them.
256 diff3_run (argc, argv, out, callbacks_arg)
260 const struct diff_callbacks *callbacks_arg;
268 struct diff_block *thread0, *thread1, *last_block;
269 char *content0, *content1;
270 struct diff3_block *diff3;
272 char *tag_strings[3];
279 callbacks = callbacks_arg;
281 initialize_main (&argc, &argv);
285 while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF)
324 if (callbacks && callbacks->write_stdout)
326 (*callbacks->write_stdout) ("diff3 - GNU diffutils version ");
327 (*callbacks->write_stdout) (diff_version_string);
328 (*callbacks->write_stdout) ("\n");
331 printf ("diff3 - GNU diffutils version %s\n", diff_version_string);
335 if (! callbacks || ! callbacks->write_stdout)
336 check_output (stdout);
339 /* Handle up to three -L options. */
342 tag_strings[tag_count++] = optarg;
345 return try_help ("Too many labels were given. The limit is 3.");
351 edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */
352 show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */
353 flagging |= ~incompat & merge;
355 if (incompat > 1 /* Ensure at most one of -AeExX3. */
356 || finalwrite & merge /* -i -m would rewrite input file. */
357 || (tag_count && ! flagging)) /* -L requires one of -AEX. */
358 return try_help ("incompatible options");
360 if (argc - optind != 3)
361 return try_help (argc - optind < 3 ? "missing operand" : "extra operand");
363 file = &argv[optind];
367 for (i = tag_count; i < 3; i++)
368 tag_strings[i] = file[i];
370 /* Always compare file1 to file2, even if file2 is "-".
371 This is needed for -mAeExX3. Using the file0 as
372 the common file would produce wrong results, because if the
373 file0-file1 diffs didn't line up with the file0-file2 diffs
374 (which is entirely possible since we don't use diff's -n option),
375 diff3 might report phantom changes from file1 to file2. */
376 /* Also try to compare file0 to file1 because this is the where
377 changes are expected to come from. Diffing between these pairs
378 of files is is most likely to return the intended changes. There
379 can also be the same problem with phantom changes from file0 to
381 /* Historically, the default common file was file2. Ediff for emacs
382 and possibly other applications, have therefore made file2 the
383 ancestor. So, for compatibility, if this is simply a three
384 way diff (not a merge or edscript) then use the old way with
385 file2 as the common file. */
389 if (edscript || merge )
397 if (strcmp (file[common], "-") == 0)
399 /* Sigh. We've got standard input as the arg corresponding to
400 the desired common file. We can't call diff twice on
401 stdin. Use another arg as the common file instead. */
403 if (strcmp (file[0], "-") == 0 || strcmp (file[common], "-") == 0)
405 diff_error ("%s", "`-' specified for more than one input file", 0);
411 mapping[1] = 3 - common;
415 for (i = 0; i < 3; i++)
416 rev_mapping[mapping[i]] = i;
418 for (i = 0; i < 3; i++)
419 if (strcmp (file[i], "-") != 0)
421 if (stat (file[i], &statb) < 0)
423 perror_with_name (file[i]);
426 else if (S_ISDIR(statb.st_mode))
428 diff_error ("%s: Is a directory", file[i], 0);
433 if (callbacks && callbacks->write_output)
437 diff_error ("write callback with output file", 0, 0);
447 outfile = fopen (out, "w");
450 perror_with_name (out);
457 /* Set the jump buffer, so that diff may abort execution without
458 terminating the process. */
459 status = setjmp (diff3_abort_buf);
463 commonname = file[rev_mapping[FILEC]];
464 thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block,
466 /* What is the intention behind determining horizon_lines from first
467 diff? I think it is better to use the same parameters for each
468 diff so that equal differences in each diff will appear the
472 for (i = 0; i < 2; i++)
474 horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i));
475 horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i));
478 thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block,
480 diff3 = make_3way_diff (thread0, thread1);
483 = output_diff3_edscript (diff3, mapping, rev_mapping,
484 tag_strings[0], tag_strings[1], tag_strings[2]);
487 FILE *mfp = fopen (file[rev_mapping[FILE0]], "r");
489 diff3_perror_with_exit (file[rev_mapping[FILE0]]);
490 conflicts_found = output_diff3_merge (mfp, diff3, mapping, rev_mapping,
491 tag_strings[0], tag_strings[1], tag_strings[2]);
493 diff3_fatal ("read error");
494 if (fclose(mfp) != 0)
495 perror_with_name (file[rev_mapping[FILE0]]);
499 output_diff3 (diff3, mapping, rev_mapping);
505 free_diff3_blocks(diff3);
507 if (! callbacks || ! callbacks->write_output)
508 check_output (outfile);
511 if (fclose (outfile) != 0)
512 perror_with_name ("close error on output file");
514 return conflicts_found;
522 diff_error ("%s", reason, 0);
523 diff_error ("Try `%s --help' for more information.", diff_program_name, 0);
528 check_output (stream)
531 if (ferror (stream) || fflush (stream) != 0)
532 diff3_fatal ("write error");
536 * Explain, patiently and kindly, how to use this program.
541 if (callbacks && callbacks->write_stdout)
543 (*callbacks->write_stdout) ("Usage: ");
544 (*callbacks->write_stdout) (diff_program_name);
545 (*callbacks->write_stdout) (" [OPTION]... MYFILE OLDFILE YOURFILE\n\n");
547 (*callbacks->write_stdout) ("\
548 -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\
549 -E --show-overlap Output unmerged changes, bracketing conflicts.\n\
550 -A --show-all Output all changes, bracketing conflicts.\n\
551 -x --overlap-only Output overlapping changes.\n\
552 -X Output overlapping changes, bracketing them.\n\
553 -3 --easy-only Output unmerged nonoverlapping changes.\n\n");
554 (*callbacks->write_stdout) ("\
555 -m --merge Output merged file instead of ed script (default -A).\n\
556 -L LABEL --label=LABEL Use LABEL instead of file name.\n\
557 -i Append `w' and `q' commands to ed scripts.\n\
558 -a --text Treat all files as text.\n\
559 -T --initial-tab Make tabs line up by prepending a tab.\n\n");
560 (*callbacks->write_stdout) ("\
561 -v --version Output version info.\n\
562 --help Output this help.\n\n");
563 (*callbacks->write_stdout) ("If a FILE is `-', read standard input.\n");
567 printf ("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n\n", diff_program_name);
570 -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\
571 -E --show-overlap Output unmerged changes, bracketing conflicts.\n\
572 -A --show-all Output all changes, bracketing conflicts.\n\
573 -x --overlap-only Output overlapping changes.\n\
574 -X Output overlapping changes, bracketing them.\n\
575 -3 --easy-only Output unmerged nonoverlapping changes.\n\n");
577 -m --merge Output merged file instead of ed script (default -A).\n\
578 -L LABEL --label=LABEL Use LABEL instead of file name.\n\
579 -i Append `w' and `q' commands to ed scripts.\n\
580 -a --text Treat all files as text.\n\
581 -T --initial-tab Make tabs line up by prepending a tab.\n\n");
583 -v --version Output version info.\n\
584 --help Output this help.\n\n");
585 printf ("If a FILE is `-', read standard input.\n");
590 * Routines that combine the two diffs together into one. The
591 * algorithm used follows:
593 * File2 is shared in common between the two diffs.
594 * Diff02 is the diff between 0 and 2.
595 * Diff12 is the diff between 1 and 2.
597 * 1) Find the range for the first block in File2.
598 * a) Take the lowest of the two ranges (in File2) in the two
599 * current blocks (one from each diff) as being the low
600 * water mark. Assign the upper end of this block as
601 * being the high water mark and move the current block up
602 * one. Mark the block just moved over as to be used.
603 * b) Check the next block in the diff that the high water
604 * mark is *not* from.
606 * *If* the high water mark is above
607 * the low end of the range in that block,
609 * mark that block as to be used and move the current
610 * block up. Set the high water mark to the max of
611 * the high end of this block and the current. Repeat b.
613 * 2) Find the corresponding ranges in File0 (from the blocks
614 * in diff02; line per line outside of diffs) and in File1.
615 * Create a diff3_block, reserving space as indicated by the ranges.
617 * 3) Copy all of the pointers for file2 in. At least for now,
618 * do memcmp's between corresponding strings in the two diffs.
620 * 4) Copy all of the pointers for file0 and 1 in. Get what you
621 * need from file2 (when there isn't a diff block, it's
622 * identical to file2 within the range between diff blocks).
624 * 5) If the diff blocks you used came from only one of the two
625 * strings of diffs, then that file (i.e. the one other than
626 * the common file in that diff) is the odd person out. If you used
627 * diff blocks from both sets, check to see if files 0 and 1 match:
629 * Same number of lines? If so, do a set of memcmp's (if a
630 * memcmp matches; copy the pointer over; it'll be easier later
631 * if you have to do any compares). If they match, 0 & 1 are
632 * the same. If not, all three different.
634 * Then you do it again, until you run out of blocks.
639 * This routine makes a three way diff (chain of diff3_block's) from two
640 * two way diffs (chains of diff_block's). It is assumed that each of
641 * the two diffs passed are onto the same file (i.e. that each of the
642 * diffs were made "to" the same file). The three way diff pointer
643 * returned will have numbering FILE0--the other file in diff02,
644 * FILE1--the other file in diff12, and FILEC--the common file.
646 static struct diff3_block *
647 make_3way_diff (thread0, thread1)
648 struct diff_block *thread0, *thread1;
651 * This routine works on the two diffs passed to it as threads.
652 * Thread number 0 is diff02, thread number 1 is diff12. The USING
653 * array is set to the base of the list of blocks to be used to
654 * construct each block of the three way diff; if no blocks from a
655 * particular thread are to be used, that element of the using array
656 * is set to 0. The elements LAST_USING array are set to the last
657 * elements on each of the using lists.
659 * The HIGH_WATER_MARK is set to the highest line number in the common file
660 * described in any of the diffs in either of the USING lists. The
661 * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK
662 * and BASE_WATER_THREAD describe the lowest line number in the common file
663 * described in any of the diffs in either of the USING lists. The
664 * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
667 * The HIGH_WATER_DIFF should always be equal to LAST_USING
668 * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for
669 * higher water, and should always be equal to
670 * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread
671 * in which the OTHER_DIFF is, and hence should always be equal to
672 * HIGH_WATER_THREAD ^ 0x1.
674 * The variable LAST_DIFF is kept set to the last diff block produced
675 * by this routine, for line correspondence purposes between that diff
676 * and the one currently being worked on. It is initialized to
677 * ZERO_DIFF before any blocks have been created.
702 struct diff3_block const *last_diff3;
704 static struct diff3_block const zero_diff3 = { 0 };
708 result_end = &result;
709 current[0] = thread0; current[1] = thread1;
710 last_diff3 = &zero_diff3;
712 /* Sniff up the threads until we reach the end */
714 while (current[0] || current[1])
716 using[0] = using[1] = last_using[0] = last_using[1] = 0;
718 /* Setup low and high water threads, diffs, and marks. */
720 base_water_thread = 1;
721 else if (!current[1])
722 base_water_thread = 0;
725 (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
727 high_water_thread = base_water_thread;
729 high_water_diff = current[high_water_thread];
732 /* low and high waters start off same diff */
733 base_water_mark = D_LOWLINE (high_water_diff, FC);
736 high_water_mark = D_HIGHLINE (high_water_diff, FC);
738 /* Make the diff you just got info from into the using class */
739 using[high_water_thread]
740 = last_using[high_water_thread]
742 current[high_water_thread] = high_water_diff->next;
743 last_using[high_water_thread]->next = 0;
745 /* And mark the other diff */
746 other_thread = high_water_thread ^ 0x1;
747 other_diff = current[other_thread];
749 /* Shuffle up the ladder, checking the other diff to see if it
750 needs to be incorporated. */
752 && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
755 /* Incorporate this diff into the using list. Note that
756 this doesn't take it off the current list */
757 if (using[other_thread])
758 last_using[other_thread]->next = other_diff;
760 using[other_thread] = other_diff;
761 last_using[other_thread] = other_diff;
763 /* Take it off the current list. Note that this following
764 code assumes that other_diff enters it equal to
765 current[high_water_thread ^ 0x1] */
766 current[other_thread] = current[other_thread]->next;
767 other_diff->next = 0;
769 /* Set the high_water stuff
770 If this comparison is equal, then this is the last pass
771 through this loop; since diff blocks within a given
772 thread cannot overlap, the high_water_mark will be
773 *below* the range_start of either of the next diffs. */
775 if (high_water_mark < D_HIGHLINE (other_diff, FC))
777 high_water_thread ^= 1;
778 high_water_diff = other_diff;
779 high_water_mark = D_HIGHLINE (other_diff, FC);
782 /* Set the other diff */
783 other_thread = high_water_thread ^ 0x1;
784 other_diff = current[other_thread];
787 /* The using lists contain a list of all of the blocks to be
788 included in this diff3_block. Create it. */
790 tmpblock = using_to_diff3_block (using, last_using,
791 base_water_thread, high_water_thread,
793 free_diff_blocks(using[0]);
794 free_diff_blocks(using[1]);
797 diff3_fatal ("internal error: screwup in format of diff blocks");
799 /* Put it on the list. */
800 *result_end = tmpblock;
801 result_end = &tmpblock->next;
803 /* Set up corresponding lines correctly. */
804 last_diff3 = tmpblock;
810 * using_to_diff3_block:
811 * This routine takes two lists of blocks (from two separate diff
812 * threads) and puts them together into one diff3 block.
813 * It then returns a pointer to this diff3 block or 0 for failure.
815 * All arguments besides using are for the convenience of the routine;
816 * they could be derived from the using array.
817 * LAST_USING is a pair of pointers to the last blocks in the using
819 * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
820 * and highest line numbers for File0.
821 * last_diff3 contains the last diff produced in the calling routine.
822 * This is used for lines mappings which would still be identical to
823 * the state that diff ended in.
825 * A distinction should be made in this routine between the two diffs
826 * that are part of a normal two diff block, and the three diffs that
827 * are part of a diff3_block.
829 static struct diff3_block *
830 using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3)
834 int low_thread, high_thread;
835 struct diff3_block const *last_diff3;
838 struct diff3_block *result;
839 struct diff_block *ptr;
842 /* Find the range in the common file. */
843 int lowc = D_LOWLINE (using[low_thread], FC);
844 int highc = D_HIGHLINE (last_using[high_thread], FC);
846 /* Find the ranges in the other files.
847 If using[d] is null, that means that the file to which that diff
848 refers is equivalent to the common file over this range. */
850 for (d = 0; d < 2; d++)
853 low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
854 high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
858 low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
859 high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
862 /* Create a block with the appropriate sizes */
863 result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
865 /* Copy information for the common file.
866 Return with a zero if any of the compares failed. */
868 for (d = 0; d < 2; d++)
869 for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
871 int result_offset = D_LOWLINE (ptr, FC) - lowc;
873 if (!copy_stringlist (D_LINEARRAY (ptr, FC),
874 D_LENARRAY (ptr, FC),
875 D_LINEARRAY (result, FILEC) + result_offset,
876 D_LENARRAY (result, FILEC) + result_offset,
877 D_NUMLINES (ptr, FC)))
881 /* Copy information for file d. First deal with anything that might be
882 before the first diff. */
884 for (d = 0; d < 2; d++)
886 struct diff_block *u = using[d];
887 int lo = low[d], hi = high[d];
890 i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
893 D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
894 D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
897 for (ptr = u; ptr; ptr = D_NEXT (ptr))
899 int result_offset = D_LOWLINE (ptr, FO) - lo;
902 if (!copy_stringlist (D_LINEARRAY (ptr, FO),
903 D_LENARRAY (ptr, FO),
904 D_LINEARRAY (result, FILE0 + d) + result_offset,
905 D_LENARRAY (result, FILE0 + d) + result_offset,
906 D_NUMLINES (ptr, FO)))
909 /* Catch the lines between here and the next diff */
910 linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
911 for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
912 i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
915 D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
916 D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
924 D3_TYPE (result) = DIFF_2ND;
926 D3_TYPE (result) = DIFF_1ST;
929 int nl0 = D_NUMLINES (result, FILE0);
930 int nl1 = D_NUMLINES (result, FILE1);
933 || !compare_line_list (D_LINEARRAY (result, FILE0),
934 D_LENARRAY (result, FILE0),
935 D_LINEARRAY (result, FILE1),
936 D_LENARRAY (result, FILE1),
938 D3_TYPE (result) = DIFF_ALL;
940 D3_TYPE (result) = DIFF_3RD;
947 * This routine copies pointers from a list of strings to a different list
948 * of strings. If a spot in the second list is already filled, it
949 * makes sure that it is filled with the same string; if not it
950 * returns 0, the copy incomplete.
951 * Upon successful completion of the copy, it returns 1.
954 copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
955 char * const fromptrs[];
957 size_t const fromlengths[];
961 register char * const *f = fromptrs;
962 register char **t = toptrs;
963 register size_t const *fl = fromlengths;
964 register size_t *tl = tolengths;
969 { if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; }
971 { *t = *f ; *tl = *fl; }
973 t++; f++; tl++; fl++;
979 * Create a diff3_block, with ranges as specified in the arguments.
980 * Allocate the arrays for the various pointers (and zero them) based
981 * on the arguments passed. Return the block as a result.
983 static struct diff3_block *
984 create_diff3_block (low0, high0, low1, high1, low2, high2)
985 register int low0, high0, low1, high1, low2, high2;
987 struct diff3_block *result = ALLOCATE (1, struct diff3_block);
990 D3_TYPE (result) = ERROR;
994 D_LOWLINE (result, FILE0) = low0;
995 D_HIGHLINE (result, FILE0) = high0;
996 D_LOWLINE (result, FILE1) = low1;
997 D_HIGHLINE (result, FILE1) = high1;
998 D_LOWLINE (result, FILE2) = low2;
999 D_HIGHLINE (result, FILE2) = high2;
1001 /* Allocate and zero space */
1002 numlines = D_NUMLINES (result, FILE0);
1005 D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *);
1006 D_LENARRAY (result, FILE0) = ALLOCATE (numlines, size_t);
1007 bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)));
1008 bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (size_t)));
1012 D_LINEARRAY (result, FILE0) = 0;
1013 D_LENARRAY (result, FILE0) = 0;
1016 numlines = D_NUMLINES (result, FILE1);
1019 D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *);
1020 D_LENARRAY (result, FILE1) = ALLOCATE (numlines, size_t);
1021 bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)));
1022 bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (size_t)));
1026 D_LINEARRAY (result, FILE1) = 0;
1027 D_LENARRAY (result, FILE1) = 0;
1030 numlines = D_NUMLINES (result, FILE2);
1033 D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *);
1034 D_LENARRAY (result, FILE2) = ALLOCATE (numlines, size_t);
1035 bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)));
1036 bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (size_t)));
1040 D_LINEARRAY (result, FILE2) = 0;
1041 D_LENARRAY (result, FILE2) = 0;
1049 * Compare two lists of lines of text.
1050 * Return 1 if they are equivalent, 0 if not.
1053 compare_line_list (list1, lengths1, list2, lengths2, nl)
1054 char * const list1[], * const list2[];
1055 size_t const lengths1[], lengths2[];
1059 * const *l1 = list1,
1060 * const *l2 = list2;
1066 if (!*l1 || !*l2 || *lgths1 != *lgths2++
1067 || memcmp (*l1++, *l2++, *lgths1++))
1073 * Routines to input and parse two way diffs.
1076 extern char **environ;
1078 static struct diff_block *
1079 process_diff (filea, fileb, last_block, diff_contents)
1080 char const *filea, *fileb;
1081 struct diff_block **last_block;
1082 char **diff_contents;
1088 struct diff_block *block_list, **block_list_end, *bptr;
1090 diff_limit = read_diff (filea, fileb, diff_contents);
1091 scan_diff = *diff_contents;
1092 block_list_end = &block_list;
1093 bptr = 0; /* Pacify `gcc -W'. */
1095 while (scan_diff < diff_limit)
1097 bptr = ALLOCATE (1, struct diff_block);
1098 bptr->lines[0] = bptr->lines[1] = 0;
1099 bptr->lengths[0] = bptr->lengths[1] = 0;
1101 dt = process_diff_control (&scan_diff, bptr);
1102 if (dt == ERROR || *scan_diff != '\n')
1106 for (serr = scan_diff; *serr != '\n'; serr++)
1109 diff_error ("diff error: %s", scan_diff, 0);
1115 /* Force appropriate ranges to be null, if necessary */
1119 bptr->ranges[0][0]++;
1122 bptr->ranges[1][0]++;
1127 diff3_fatal ("internal error: invalid diff type in process_diff");
1131 /* Allocate space for the pointers for the lines from filea, and
1132 parcel them out among these pointers */
1135 int numlines = D_NUMLINES (bptr, 0);
1136 bptr->lines[0] = ALLOCATE (numlines, char *);
1137 bptr->lengths[0] = ALLOCATE (numlines, size_t);
1138 for (i = 0; i < numlines; i++)
1139 scan_diff = scan_diff_line (scan_diff,
1140 &(bptr->lines[0][i]),
1141 &(bptr->lengths[0][i]),
1146 /* Get past the separator for changes */
1149 if (strncmp (scan_diff, "---\n", 4))
1150 diff3_fatal ("invalid diff format; invalid change separator");
1154 /* Allocate space for the pointers for the lines from fileb, and
1155 parcel them out among these pointers */
1158 int numlines = D_NUMLINES (bptr, 1);
1159 bptr->lines[1] = ALLOCATE (numlines, char *);
1160 bptr->lengths[1] = ALLOCATE (numlines, size_t);
1161 for (i = 0; i < numlines; i++)
1162 scan_diff = scan_diff_line (scan_diff,
1163 &(bptr->lines[1][i]),
1164 &(bptr->lengths[1][i]),
1169 /* Place this block on the blocklist. */
1170 *block_list_end = bptr;
1171 block_list_end = &bptr->next;
1174 *block_list_end = 0;
1180 * This routine will parse a normal format diff control string. It
1181 * returns the type of the diff (ERROR if the format is bad). All of
1182 * the other important information is filled into to the structure
1183 * pointed to by db, and the string pointer (whose location is passed
1184 * to this routine) is updated to point beyond the end of the string
1185 * parsed. Note that only the ranges in the diff_block will be set by
1188 * If some specific pair of numbers has been reduced to a single
1189 * number, then both corresponding numbers in the diff block are set
1190 * to that number. In general these numbers are interpetted as ranges
1191 * inclusive, unless being used by the ADD or DELETE commands. It is
1192 * assumed that these will be special cased in a superior routine.
1195 static enum diff_type
1196 process_diff_control (string, db)
1198 struct diff_block *db;
1202 enum diff_type type;
1204 /* These macros are defined here because they can use variables
1205 defined in this function. Don't try this at home kids, we're
1206 trained professionals!
1208 Also note that SKIPWHITE only recognizes tabs and spaces, and
1209 that READNUM can only read positive, integral numbers */
1211 #define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; }
1212 #define READNUM(s, num) \
1213 { unsigned char c = *s; if (!ISDIGIT (c)) return ERROR; holdnum = 0; \
1214 do { holdnum = (c - '0' + holdnum * 10); } \
1215 while (ISDIGIT (c = *++s)); (num) = holdnum; }
1217 /* Read first set of digits */
1219 READNUM (s, db->ranges[0][START]);
1221 /* Was that the only digit? */
1225 /* Get the next digit */
1227 READNUM (s, db->ranges[0][END]);
1230 db->ranges[0][END] = db->ranges[0][START];
1232 /* Get the letter */
1246 return ERROR; /* Bad format */
1248 s++; /* Past letter */
1250 /* Read second set of digits */
1252 READNUM (s, db->ranges[1][START]);
1254 /* Was that the only digit? */
1258 /* Get the next digit */
1260 READNUM (s, db->ranges[1][END]);
1261 SKIPWHITE (s); /* To move to end */
1264 db->ranges[1][END] = db->ranges[1][START];
1271 read_diff (filea, fileb, output_placement)
1272 char const *filea, *fileb;
1273 char **output_placement;
1276 size_t bytes, current_chunk_size, total;
1278 struct stat pipestat;
1280 const struct diff_callbacks *callbacks_hold;
1281 struct diff_callbacks my_callbacks;
1282 struct diff_callbacks *my_callbacks_arg;
1284 /* 302 / 1000 is log10(2.0) rounded up. Subtract 1 for the sign bit;
1285 add 1 for integer division truncation; add 1 more for a minus sign. */
1286 #define INT_STRLEN_BOUND(type) ((sizeof(type)*CHAR_BIT - 1) * 302 / 1000 + 2)
1288 char const *argv[7];
1289 char horizon_arg[17 + INT_STRLEN_BOUND (int)];
1297 sprintf (horizon_arg, "--horizon-lines=%d", horizon_lines);
1298 *ap++ = horizon_arg;
1304 diffout = cvs_temp_name ();
1306 outfile_hold = outfile;
1307 callbacks_hold = callbacks;
1309 /* We want to call diff_run preserving any stdout and stderr
1310 callbacks, but discarding any callbacks to handle file output,
1311 since we want the file output to go to our temporary file.
1312 FIXME: We should use callbacks to just read it into a memory
1313 buffer; that's we do with the temporary file just below anyhow. */
1314 if (callbacks == NULL)
1315 my_callbacks_arg = NULL;
1318 my_callbacks = *callbacks;
1319 my_callbacks.write_output = NULL;
1320 my_callbacks.flush_output = NULL;
1321 my_callbacks_arg = &my_callbacks;
1324 wstatus = diff_run (ap - argv, (char **) argv, diffout, my_callbacks_arg);
1326 outfile = outfile_hold;
1327 callbacks = callbacks_hold;
1330 diff3_fatal ("subsidiary diff failed");
1332 if (-1 == (fd = open (diffout, O_RDONLY)))
1333 diff3_fatal ("could not open temporary diff file");
1335 current_chunk_size = 8 * 1024;
1336 if (fstat (fd, &pipestat) == 0)
1337 current_chunk_size = max (current_chunk_size, STAT_BLOCKSIZE (pipestat));
1339 diff_result = xmalloc (current_chunk_size);
1343 diff_result + total,
1344 current_chunk_size - total);
1346 if (total == current_chunk_size)
1348 if (current_chunk_size < 2 * current_chunk_size)
1349 current_chunk_size = 2 * current_chunk_size;
1350 else if (current_chunk_size < (size_t) -1)
1351 current_chunk_size = (size_t) -1;
1353 diff3_fatal ("files are too large to fit into memory");
1354 diff_result = xrealloc (diff_result, (current_chunk_size *= 2));
1358 if (total != 0 && diff_result[total-1] != '\n')
1359 diff3_fatal ("invalid diff format; incomplete last line");
1361 *output_placement = diff_result;
1363 if (close (fd) != 0)
1364 diff3_perror_with_exit ("pipe close");
1368 return diff_result + total;
1373 * Scan a regular diff line (consisting of > or <, followed by a
1374 * space, followed by text (including nulls) up to a newline.
1376 * This next routine began life as a macro and many parameters in it
1377 * are used as call-by-reference values.
1380 scan_diff_line (scan_ptr, set_start, set_length, limit, leadingchar)
1381 char *scan_ptr, **set_start;
1388 if (!(scan_ptr[0] == leadingchar
1389 && scan_ptr[1] == ' '))
1390 diff3_fatal ("invalid diff format; incorrect leading line chars");
1392 *set_start = line_ptr = scan_ptr + 2;
1393 while (*line_ptr++ != '\n')
1396 /* Include newline if the original line ended in a newline,
1397 or if an edit script is being generated.
1398 Copy any missing newline message to stderr if an edit script is being
1399 generated, because edit scripts cannot handle missing newlines.
1400 Return the beginning of the next line. */
1401 *set_length = line_ptr - *set_start;
1402 if (line_ptr < limit && *line_ptr == '\\')
1408 while (*line_ptr++ != '\n')
1417 while (*line_ptr++ != '\n')
1419 line_ptr[-1] = '\0';
1420 diff_error ("%s", serr, 0);
1421 line_ptr[-1] = '\n';
1429 * This routine outputs a three way diff passed as a list of
1431 * The argument MAPPING is indexed by external file number (in the
1432 * argument list) and contains the internal file number (from the
1433 * diff passed). This is important because the user expects his
1434 * outputs in terms of the argument list number, and the diff passed
1435 * may have been done slightly differently (if the last argument
1436 * was "-", for example).
1437 * REV_MAPPING is the inverse of MAPPING.
1440 output_diff3 (diff, mapping, rev_mapping)
1441 struct diff3_block *diff;
1442 int const mapping[3], rev_mapping[3];
1447 struct diff3_block *ptr;
1451 static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
1452 char const *line_prefix = tab_align_flag ? "\t" : " ";
1454 for (ptr = diff; ptr; ptr = D_NEXT (ptr))
1458 switch (ptr->correspond)
1462 dontprint = 3; /* Print them all */
1463 oddoneout = 3; /* Nobody's odder than anyone else */
1468 oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST];
1470 x[0] = oddoneout + '1';
1472 dontprint = oddoneout==0;
1475 diff3_fatal ("internal error: invalid diff type passed to output");
1477 printf_output ("====%s\n", x);
1479 /* Go 0, 2, 1 if the first and third outputs are equivalent. */
1481 i = (oddoneout == 1 ? skew_increment[i] : i + 1))
1483 int realfile = mapping[i];
1485 lowt = D_LOWLINE (ptr, realfile),
1486 hight = D_HIGHLINE (ptr, realfile);
1488 printf_output ("%d:", i + 1);
1489 switch (lowt - hight)
1492 printf_output ("%da\n", lowt - 1);
1495 printf_output ("%dc\n", lowt);
1498 printf_output ("%d,%dc\n", lowt, hight);
1502 if (i == dontprint) continue;
1509 printf_output (line_prefix);
1510 cp = D_RELNUM (ptr, realfile, line);
1511 length = D_RELLEN (ptr, realfile, line);
1512 write_output (cp, length);
1514 while (++line < hight - lowt + 1);
1515 if (cp[length - 1] != '\n')
1516 printf_output ("\n\\ No newline at end of file\n");
1524 * Output the lines of B taken from FILENUM.
1525 * Double any initial '.'s; yield nonzero if any initial '.'s were doubled.
1528 dotlines (b, filenum)
1529 struct diff3_block *b;
1533 int leading_dot = 0;
1536 i < D_NUMLINES (b, filenum);
1539 char *line = D_RELNUM (b, filenum, i);
1543 write_output (".", 1);
1545 write_output (line, D_RELLEN (b, filenum, i));
1552 * Output to OUTPUTFILE a '.' line. If LEADING_DOT is nonzero,
1553 * also output a command that removes initial '.'s
1554 * starting with line START and continuing for NUM lines.
1557 undotlines (leading_dot, start, num)
1558 int leading_dot, start, num;
1560 write_output (".\n", 2);
1563 printf_output ("%ds/^\\.//\n", start);
1565 printf_output ("%d,%ds/^\\.//\n", start, start + num - 1);
1569 * This routine outputs a diff3 set of blocks as an ed script. This
1570 * script applies the changes between file's 2 & 3 to file 1. It
1571 * takes the precise format of the ed script to be output from global
1572 * variables set during options processing. Note that it does
1573 * destructive things to the set of diff3 blocks it is passed; it
1574 * reverses their order (this gets around the problems involved with
1575 * changing line numbers in an ed script).
1577 * Note that this routine has the same problem of mapping as the last
1578 * one did; the variable MAPPING maps from file number according to
1579 * the argument list to file number according to the diff passed. All
1580 * files listed below are in terms of the argument list.
1581 * REV_MAPPING is the inverse of MAPPING.
1583 * The arguments FILE0, FILE1 and FILE2 are the strings to print
1584 * as the names of the three files. These may be the actual names,
1585 * or may be the arguments specified with -L.
1587 * Returns 1 if conflicts were found.
1591 output_diff3_edscript (diff, mapping, rev_mapping, file0, file1, file2)
1592 struct diff3_block *diff;
1593 int const mapping[3], rev_mapping[3];
1594 char const *file0, *file1, *file2;
1597 int conflicts_found = 0, conflict;
1598 struct diff3_block *b;
1600 for (b = reverse_diff3_blocklist (diff); b; b = b->next)
1602 /* Must do mapping correctly. */
1604 = ((b->correspond == DIFF_ALL) ?
1608 + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
1610 /* If we aren't supposed to do this output block, skip it. */
1614 case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
1615 case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
1616 case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
1621 conflicts_found = 1;
1624 /* Mark end of conflict. */
1626 printf_output ("%da\n", D_HIGHLINE (b, mapping[FILE0]));
1628 if (type == DIFF_ALL)
1632 /* Append lines from FILE1. */
1633 printf_output ("||||||| %s\n", file1);
1634 leading_dot = dotlines (b, mapping[FILE1]);
1636 /* Append lines from FILE2. */
1637 printf_output ("=======\n");
1638 leading_dot |= dotlines (b, mapping[FILE2]);
1640 printf_output (">>>>>>> %s\n", file2);
1641 undotlines (leading_dot,
1642 D_HIGHLINE (b, mapping[FILE0]) + 2,
1643 (D_NUMLINES (b, mapping[FILE1])
1644 + D_NUMLINES (b, mapping[FILE2]) + 1));
1647 /* Mark start of conflict. */
1649 printf_output ("%da\n<<<<<<< %s\n",
1650 D_LOWLINE (b, mapping[FILE0]) - 1,
1651 type == DIFF_ALL ? file0 : file1);
1653 if (type == DIFF_2ND)
1655 /* Prepend lines from FILE1. */
1656 leading_dot = dotlines (b, mapping[FILE1]);
1657 printf_output ("=======\n");
1659 undotlines (leading_dot,
1660 D_LOWLINE (b, mapping[FILE0]) + 1,
1661 D_NUMLINES (b, mapping[FILE1]));
1663 else if (D_NUMLINES (b, mapping[FILE2]) == 0)
1664 /* Write out a delete */
1666 if (D_NUMLINES (b, mapping[FILE0]) == 1)
1667 printf_output ("%dd\n", D_LOWLINE (b, mapping[FILE0]));
1669 printf_output ("%d,%dd\n",
1670 D_LOWLINE (b, mapping[FILE0]),
1671 D_HIGHLINE (b, mapping[FILE0]));
1674 /* Write out an add or change */
1676 switch (D_NUMLINES (b, mapping[FILE0]))
1679 printf_output ("%da\n", D_HIGHLINE (b, mapping[FILE0]));
1682 printf_output ("%dc\n", D_HIGHLINE (b, mapping[FILE0]));
1685 printf_output ("%d,%dc\n",
1686 D_LOWLINE (b, mapping[FILE0]),
1687 D_HIGHLINE (b, mapping[FILE0]));
1691 undotlines (dotlines (b, mapping[FILE2]),
1692 D_LOWLINE (b, mapping[FILE0]),
1693 D_NUMLINES (b, mapping[FILE2]));
1696 if (finalwrite) printf_output ("w\nq\n");
1697 return conflicts_found;
1701 * Read from INFILE and output to the standard output file a set of
1702 * diff3_ blocks DIFF as a merged file. This acts like 'ed file0
1703 * <[output_diff3_edscript]', except that it works even for binary
1704 * data or incomplete lines.
1706 * As before, MAPPING maps from arg list file number to diff file number,
1707 * REV_MAPPING is its inverse,
1708 * and FILE0, FILE1, and FILE2 are the names of the files.
1710 * Returns 1 if conflicts were found.
1714 output_diff3_merge (infile, diff, mapping, rev_mapping,
1715 file0, file1, file2)
1717 struct diff3_block *diff;
1718 int const mapping[3], rev_mapping[3];
1719 char const *file0, *file1, *file2;
1723 int conflicts_found = 0, conflict;
1724 struct diff3_block *b;
1727 for (b = diff; b; b = b->next)
1729 /* Must do mapping correctly. */
1731 = ((b->correspond == DIFF_ALL) ?
1735 + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
1736 char const *format_2nd = "<<<<<<< %s\n";
1738 /* If we aren't supposed to do this output block, skip it. */
1742 case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
1743 case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
1744 case DIFF_ALL: if (simple_only) continue; conflict = flagging;
1745 format_2nd = "||||||| %s\n";
1749 /* Copy I lines from file 0. */
1750 i = D_LOWLINE (b, FILE0) - linesread - 1;
1757 if (ferror (infile))
1758 diff3_perror_with_exit ("input file");
1759 else if (feof (infile))
1760 diff3_fatal ("input file shrank");
1762 write_output (&cc, 1);
1768 conflicts_found = 1;
1770 if (type == DIFF_ALL)
1772 /* Put in lines from FILE0 with bracket. */
1773 printf_output ("<<<<<<< %s\n", file0);
1775 i < D_NUMLINES (b, mapping[FILE0]);
1777 write_output (D_RELNUM (b, mapping[FILE0], i),
1778 D_RELLEN (b, mapping[FILE0], i));
1783 /* Put in lines from FILE1 with bracket. */
1784 printf_output (format_2nd, file1);
1786 i < D_NUMLINES (b, mapping[FILE1]);
1788 write_output (D_RELNUM (b, mapping[FILE1], i),
1789 D_RELLEN (b, mapping[FILE1], i));
1792 printf_output ("=======\n");
1795 /* Put in lines from FILE2. */
1797 i < D_NUMLINES (b, mapping[FILE2]);
1799 write_output (D_RELNUM (b, mapping[FILE2], i),
1800 D_RELLEN (b, mapping[FILE2], i));
1803 printf_output (">>>>>>> %s\n", file2);
1805 /* Skip I lines in file 0. */
1806 i = D_NUMLINES (b, FILE0);
1809 while ((c = getc (infile)) != '\n')
1811 if (ferror (infile))
1812 diff3_perror_with_exit ("input file");
1813 else if (feof (infile))
1816 diff3_fatal ("input file shrank");
1817 return conflicts_found;
1820 /* Copy rest of common file. */
1821 while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
1824 write_output (&cc, 1);
1826 return conflicts_found;
1830 * Reverse the order of the list of diff3 blocks.
1832 static struct diff3_block *
1833 reverse_diff3_blocklist (diff)
1834 struct diff3_block *diff;
1836 register struct diff3_block *tmp, *next, *prev;
1838 for (tmp = diff, prev = 0; tmp; tmp = next)
1849 myread (fd, ptr, size)
1854 ssize_t result = read (fd, ptr, size);
1856 diff3_perror_with_exit ("read failed");
1857 return (size_t)result;
1861 diff3_fatal (string)
1864 diff_error ("%s", string, 0);
1869 diff3_perror_with_exit (string)
1872 perror_with_name (string);
1877 initialize_main (argcp, argvp)
1890 diff_program_name = (*argvp)[0];
1896 struct diff_block *p;
1898 register struct diff_block *next;
1903 if (p->lines[0]) free(p->lines[0]);
1904 if (p->lines[1]) free(p->lines[1]);
1905 if (p->lengths[0]) free(p->lengths[0]);
1906 if (p->lengths[1]) free(p->lengths[1]);
1913 free_diff3_blocks(p)
1914 struct diff3_block *p;
1916 register struct diff3_block *next;
1921 if (p->lines[0]) free(p->lines[0]);
1922 if (p->lines[1]) free(p->lines[1]);
1923 if (p->lines[2]) free(p->lines[2]);
1924 if (p->lengths[0]) free(p->lengths[0]);
1925 if (p->lengths[1]) free(p->lengths[1]);
1926 if (p->lengths[2]) free(p->lengths[2]);