Sync usage with man page.
[netbsd-mini2440.git] / gnu / dist / diffutils / src / diff3.c
blob70fea19d46325dc590cd54ea3697f9b8ec833a99
1 /* $NetBSD$ */
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)
11 any later version.
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. */
23 #include "system.h"
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.");
30 #include <c-stack.h>
31 #include <cmpbuf.h>
32 #include <error.h>
33 #include <exitfail.h>
34 #include <freesoft.h>
35 #include <getopt.h>
36 #include <inttostr.h>
37 #include <quotesys.h>
38 #include <stdio.h>
39 #include <xalloc.h>
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. */
49 #define FILE0 0
50 #define FILE1 1
51 #define FILE2 2
54 * A three way diff is built from two two-way diffs; the file which
55 * the two two-way diffs share is:
57 #define FILEC FILE2
60 * Different files within a two way diff.
61 * FC is the common file, FO the other file.
63 #define FO 0
64 #define FC 1
66 /* The ranges are indexed by */
67 #define RANGE_START 0
68 #define RANGE_END 1
70 enum diff_type {
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 */
81 /* Two way diff */
82 struct diff_block {
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;
89 /* Three way diff */
91 struct diff3_block {
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])
128 * Next block.
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) \
142 ((linenum) \
143 - D_HIGHLINE ((diff), (fromfile)) \
144 + D_HIGHLINE ((diff), (tofile)))
146 #define D_LOW_MAPLINE(diff, fromfile, tofile, linenum) \
147 ((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. */
154 static bool text;
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. */
181 static bool merge;
183 char *program_name;
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. */
207 enum
209 DIFF_PROGRAM_OPTION = CHAR_MAX + 1,
210 HELP_OPTION
213 static struct option const longopts[] =
215 {"text", 0, 0, 'a'},
216 {"show-all", 0, 0, 'A'},
217 {"ed", 0, 0, 'e'},
218 {"diff-program", 1, 0, DIFF_PROGRAM_OPTION},
219 {"show-overlap", 0, 0, 'E'},
220 {"label", 1, 0, 'L'},
221 {"merge", 0, 0, 'm'},
222 {"initial-tab", 0, 0, 'T'},
223 {"overlap-only", 0, 0, 'x'},
224 {"easy-only", 0, 0, '3'},
225 {"version", 0, 0, 'v'},
226 {"help", 0, 0, HELP_OPTION},
227 {0, 0, 0, 0}
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)
237 int c, i;
238 int common;
239 int mapping[3];
240 int rev_mapping[3];
241 int incompat = 0;
242 bool conflicts_found;
243 struct diff_block *thread0, *thread1, *last_block;
244 struct diff3_block *diff3;
245 int tag_count = 0;
246 char *tag_strings[3];
247 char *commonname;
248 char **file;
249 struct stat statb;
251 exit_failure = 2;
252 initialize_main (&argc, &argv);
253 program_name = argv[0];
254 setlocale (LC_ALL, "");
255 bindtextdomain (PACKAGE, LOCALEDIR);
256 textdomain (PACKAGE);
257 c_stack_action (c_stack_die);
259 while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != -1)
261 switch (c)
263 case 'a':
264 text = 1;
265 break;
266 case 'A':
267 show_2nd = 1;
268 flagging = 1;
269 incompat++;
270 break;
271 case 'x':
272 overlap_only = 1;
273 incompat++;
274 break;
275 case '3':
276 simple_only = 1;
277 incompat++;
278 break;
279 case 'i':
280 finalwrite = 1;
281 break;
282 case 'm':
283 merge = 1;
284 break;
285 case 'X':
286 overlap_only = 1;
287 /* Fall through. */
288 case 'E':
289 flagging = 1;
290 /* Fall through. */
291 case 'e':
292 incompat++;
293 break;
294 case 'T':
295 initial_tab = 1;
296 break;
297 case 'v':
298 printf ("diff3 %s\n%s\n\n%s\n\n%s\n",
299 version_string, copyright_string,
300 _(free_software_msgid), _(authorship_msgid));
301 check_stdout ();
302 return EXIT_SUCCESS;
303 case DIFF_PROGRAM_OPTION:
304 diff_program = optarg;
305 break;
306 case HELP_OPTION:
307 usage ();
308 check_stdout ();
309 return EXIT_SUCCESS;
310 case 'L':
311 /* Handle up to three -L options. */
312 if (tag_count < 3)
314 tag_strings[tag_count++] = optarg;
315 break;
317 try_help ("too many file label options", 0);
318 default:
319 try_help (0, 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]);
336 else
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
367 file instead. */
368 common = 3 - common;
369 if (strcmp (file[0], "-") == 0 || strcmp (file[common], "-") == 0)
370 fatal ("`-' specified for more than one input file");
373 mapping[0] = 0;
374 mapping[1] = 3 - common;
375 mapping[2] = 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]);
389 #ifdef SIGCHLD
390 /* System V fork+wait does not work if SIGCHLD is ignored. */
391 signal (SIGCHLD, SIG_DFL);
392 #endif
394 commonname = file[rev_mapping[FILEC]];
395 thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
396 thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block);
397 diff3 = make_3way_diff (thread0, thread1);
398 if (edscript)
399 conflicts_found
400 = output_diff3_edscript (stdout, diff3, mapping, rev_mapping,
401 tag_strings[0], tag_strings[1], tag_strings[2]);
402 else if (merge)
404 if (! freopen (file[rev_mapping[FILE0]], "r", stdin))
405 perror_with_exit (file[rev_mapping[FILE0]]);
406 conflicts_found
407 = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping,
408 tag_strings[0], tag_strings[1], tag_strings[2]);
409 if (ferror (stdin))
410 fatal ("read failed");
412 else
414 output_diff3 (stdout, diff3, mapping, rev_mapping);
415 conflicts_found = 0;
418 check_stdout ();
419 exit (conflicts_found);
420 return conflicts_found;
423 static void
424 try_help (char const *reason_msgid, char const *operand)
426 if (reason_msgid)
427 error (0, 0, _(reason_msgid), operand);
428 error (EXIT_TROUBLE, 0,
429 _("Try `%s --help' for more information."), program_name);
430 abort ();
433 static void
434 check_stdout (void)
436 if (ferror (stdout))
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."),
462 static void
463 usage (void)
465 char const * const *p;
467 printf (_("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n"),
468 program_name);
469 printf ("%s\n\n", _("Compare three files line by line."));
470 for (p = option_help_msgid; *p; p++)
471 if (**p)
472 printf (" %s\n", _(*p));
473 else
474 putchar ('\n');
475 printf ("\n%s\n\n%s\n",
476 _("If a FILE is `-', read standard input."),
477 _("Report bugs to <bug-gnu-utils@gnu.org>."));
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
555 * taken.
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];
574 lin high_water_mark;
576 int high_water_thread;
577 int base_water_thread;
578 int other_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;
591 /* Initialization */
592 result = 0;
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. */
604 if (!current[0])
605 base_water_thread = 1;
606 else if (!current[1])
607 base_water_thread = 0;
608 else
609 base_water_thread =
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]
621 = high_water_diff;
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. */
631 while (other_diff
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;
639 else
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,
672 last_diff3);
674 if (!tmpblock)
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;
684 return result;
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
696 * structure.
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)
713 lin low[2], high[2];
714 struct diff3_block *result;
715 struct diff_block *ptr;
716 int d;
717 lin i;
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++)
728 if (using[d])
730 low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
731 high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
733 else
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)))
755 return 0;
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];
766 for (i = 0;
767 i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
768 i++)
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;
777 lin linec;
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)))
784 return 0;
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;
790 i++)
792 D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
793 D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
794 linec++;
799 /* Set correspond */
800 if (!using[0])
801 D3_TYPE (result) = DIFF_2ND;
802 else if (!using[1])
803 D3_TYPE (result) = DIFF_1ST;
804 else
806 lin nl0 = D_NUMLINES (result, FILE0);
807 lin nl1 = D_NUMLINES (result, FILE1);
809 if (nl0 != nl1
810 || !compare_line_list (D_LINEARRAY (result, FILE0),
811 D_LENARRAY (result, FILE0),
812 D_LINEARRAY (result, FILE1),
813 D_LENARRAY (result, FILE1),
814 nl0))
815 D3_TYPE (result) = DIFF_ALL;
816 else
817 D3_TYPE (result) = DIFF_3RD;
820 return result;
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.
830 static bool
831 copy_stringlist (char * const fromptrs[], size_t const fromlengths[],
832 char *toptrs[], size_t tolengths[],
833 lin copynum)
835 register char * const *f = fromptrs;
836 register char **t = toptrs;
837 register size_t const *fl = fromlengths;
838 register size_t *tl = tolengths;
840 while (copynum--)
842 if (*t)
843 { if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; }
844 else
845 { *t = *f ; *tl = *fl; }
847 t++; f++; tl++; fl++;
849 return 1;
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,
859 lin low1, lin high1,
860 lin low2, lin high2)
862 struct diff3_block *result = xmalloc (sizeof *result);
863 lin numlines;
865 D3_TYPE (result) = ERROR;
866 D_NEXT (result) = 0;
868 /* Assign ranges */
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);
878 if (numlines)
880 D_LINEARRAY (result, FILE0) = xcalloc (numlines, sizeof (char *));
881 D_LENARRAY (result, FILE0) = xcalloc (numlines, sizeof (size_t));
883 else
885 D_LINEARRAY (result, FILE0) = 0;
886 D_LENARRAY (result, FILE0) = 0;
889 numlines = D_NUMLINES (result, FILE1);
890 if (numlines)
892 D_LINEARRAY (result, FILE1) = xcalloc (numlines, sizeof (char *));
893 D_LENARRAY (result, FILE1) = xcalloc (numlines, sizeof (size_t));
895 else
897 D_LINEARRAY (result, FILE1) = 0;
898 D_LENARRAY (result, FILE1) = 0;
901 numlines = D_NUMLINES (result, FILE2);
902 if (numlines)
904 D_LINEARRAY (result, FILE2) = xcalloc (numlines, sizeof (char *));
905 D_LENARRAY (result, FILE2) = xcalloc (numlines, sizeof (size_t));
907 else
909 D_LINEARRAY (result, FILE2) = 0;
910 D_LENARRAY (result, FILE2) = 0;
913 /* Return */
914 return result;
918 * Compare two lists of lines of text.
919 * Return 1 if they are equivalent, 0 if not.
921 static bool
922 compare_line_list (char * const list1[], size_t const lengths1[],
923 char * const list2[], size_t const lengths2[],
924 lin nl)
926 char
927 * const *l1 = list1,
928 * const *l2 = list2;
929 size_t const
930 *lgths1 = lengths1,
931 *lgths2 = lengths2;
933 while (nl--)
934 if (!*l1 || !*l2 || *lgths1 != *lgths2++
935 || memcmp (*l1++, *l2++, *lgths1++))
936 return 0;
937 return 1;
941 * Routines to input and parse two way diffs.
944 static struct diff_block *
945 process_diff (char const *filea,
946 char const *fileb,
947 struct diff_block **last_block)
949 char *diff_contents;
950 char *diff_limit;
951 char *scan_diff;
952 enum diff_type dt;
953 lin i;
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');
979 exit (EXIT_TROUBLE);
981 scan_diff++;
983 /* Force appropriate ranges to be null, if necessary */
984 switch (dt)
986 case ADD:
987 bptr->ranges[0][0]++;
988 break;
989 case DELETE:
990 bptr->ranges[1][0]++;
991 break;
992 case CHANGE:
993 break;
994 default:
995 fatal ("internal error: invalid diff type in process_diff");
996 break;
999 /* Allocate space for the pointers for the lines from filea, and
1000 parcel them out among these pointers */
1001 if (dt != ADD)
1003 lin numlines = D_NUMLINES (bptr, 0);
1004 if (too_many_lines <= numlines)
1005 xalloc_die ();
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]),
1012 diff_limit,
1013 '<');
1016 /* Get past the separator for changes */
1017 if (dt == CHANGE)
1019 if (strncmp (scan_diff, "---\n", 4))
1020 fatal ("invalid diff format; invalid change separator");
1021 scan_diff += 4;
1024 /* Allocate space for the pointers for the lines from fileb, and
1025 parcel them out among these pointers */
1026 if (dt != DELETE)
1028 lin numlines = D_NUMLINES (bptr, 1);
1029 if (too_many_lines <= numlines)
1030 xalloc_die ();
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]),
1037 diff_limit,
1038 '>');
1041 /* Place this block on the blocklist. */
1042 *block_list_end = bptr;
1043 block_list_end = &bptr->next;
1046 *block_list_end = 0;
1047 *last_block = bptr;
1048 return block_list;
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
1058 * this routine.
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)
1070 char *s = *string;
1071 lin holdnum;
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 */
1088 SKIPWHITE (s);
1089 READNUM (s, db->ranges[0][RANGE_START]);
1091 /* Was that the only digit? */
1092 SKIPWHITE (s);
1093 if (*s == ',')
1095 /* Get the next digit */
1096 s++;
1097 READNUM (s, db->ranges[0][RANGE_END]);
1099 else
1100 db->ranges[0][RANGE_END] = db->ranges[0][RANGE_START];
1102 /* Get the letter */
1103 SKIPWHITE (s);
1104 switch (*s)
1106 case 'a':
1107 type = ADD;
1108 break;
1109 case 'c':
1110 type = CHANGE;
1111 break;
1112 case 'd':
1113 type = DELETE;
1114 break;
1115 default:
1116 return ERROR; /* Bad format */
1118 s++; /* Past letter */
1120 /* Read second set of digits */
1121 SKIPWHITE (s);
1122 READNUM (s, db->ranges[1][RANGE_START]);
1124 /* Was that the only digit? */
1125 SKIPWHITE (s);
1126 if (*s == ',')
1128 /* Get the next digit */
1129 s++;
1130 READNUM (s, db->ranges[1][RANGE_END]);
1131 SKIPWHITE (s); /* To move to end */
1133 else
1134 db->ranges[1][RANGE_END] = db->ranges[1][RANGE_START];
1136 *string = s;
1137 return type;
1140 static char *
1141 read_diff (char const *filea,
1142 char const *fileb,
1143 char **output_placement)
1145 char *diff_result;
1146 size_t current_chunk_size, total;
1147 int fd, wstatus;
1148 int werrno = 0;
1149 struct stat pipestat;
1151 #if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
1153 char const *argv[8];
1154 char const **ap;
1155 int fds[2];
1156 pid_t pid;
1158 ap = argv;
1159 *ap++ = diff_program;
1160 if (text)
1161 *ap++ = "-a";
1162 *ap++ = "--horizon-lines=100";
1163 *ap++ = "--";
1164 *ap++ = filea;
1165 *ap++ = fileb;
1166 *ap = 0;
1168 if (pipe (fds) != 0)
1169 perror_with_exit ("pipe");
1171 pid = vfork ();
1172 if (pid == 0)
1174 /* Child */
1175 close (fds[0]);
1176 if (fds[1] != STDOUT_FILENO)
1178 dup2 (fds[1], STDOUT_FILENO);
1179 close (fds[1]);
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);
1189 if (pid == -1)
1190 perror_with_exit ("fork");
1192 close (fds[1]); /* Prevent erroneous lack of EOF */
1193 fd = fds[0];
1195 #else
1197 FILE *fpipe;
1198 char const args[] = " -a --horizon-lines=100 -- ";
1199 char *command = xmalloc (quote_system_arg (0, diff_program)
1200 + sizeof args - 1
1201 + quote_system_arg (0, filea) + 1
1202 + quote_system_arg (0, fileb) + 1);
1203 char *p = command;
1204 p += quote_system_arg (p, diff_program);
1205 strcpy (p, args + (text ? 0 : 3));
1206 p += strlen (p);
1207 p += quote_system_arg (p, filea);
1208 *p++ = ' ';
1209 p += quote_system_arg (p, fileb);
1210 *p = 0;
1211 errno = 0;
1212 fpipe = popen (command, "r");
1213 if (!fpipe)
1214 perror_with_exit (command);
1215 free (command);
1216 fd = fileno (fpipe);
1218 #endif
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);
1224 total = 0;
1226 for (;;)
1228 size_t bytes_to_read = current_chunk_size - total;
1229 size_t bytes = block_read (fd, diff_result + total, bytes_to_read);
1230 total += bytes;
1231 if (bytes != bytes_to_read)
1233 if (bytes == SIZE_MAX)
1234 perror_with_exit (_("read failed"));
1235 break;
1237 if (PTRDIFF_MAX / 2 <= current_chunk_size)
1238 xalloc_die ();
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);
1251 if (wstatus == -1)
1252 werrno = errno;
1254 #else
1256 if (close (fd) != 0)
1257 perror_with_exit ("close");
1258 if (waitpid (pid, &wstatus, 0) < 0)
1259 perror_with_exit ("waitpid");
1261 #endif
1263 if (! werrno && WIFEXITED (wstatus))
1264 switch (WEXITSTATUS (wstatus))
1266 case 126:
1267 error (EXIT_TROUBLE, 0, _("subsidiary program `%s' not executable"),
1268 diff_program);
1269 case 127:
1270 error (EXIT_TROUBLE, 0, _("subsidiary program `%s' not found"),
1271 diff_program);
1273 if (werrno || ! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
1274 error (EXIT_TROUBLE, werrno, _("subsidiary program `%s' failed"),
1275 diff_program);
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.
1288 static char *
1289 scan_diff_line (char *scan_ptr, char **set_start, size_t *set_length,
1290 char *limit, char leadingchar)
1292 char *line_ptr;
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')
1300 continue;
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 == '\\')
1310 if (edscript)
1311 fprintf (stderr, "%s:", program_name);
1312 else
1313 --*set_length;
1314 line_ptr++;
1317 if (edscript)
1318 putc (*line_ptr, stderr);
1320 while (*line_ptr++ != '\n');
1323 return line_ptr;
1327 * This routine outputs a three way diff passed as a list of
1328 * diff3_block's.
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.
1337 static void
1338 output_diff3 (FILE *outputfile, struct diff3_block *diff,
1339 int const mapping[3], int const rev_mapping[3])
1341 int i;
1342 int oddoneout;
1343 char *cp;
1344 struct diff3_block *ptr;
1345 lin line;
1346 size_t length;
1347 int dontprint;
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))
1353 char x[2];
1355 switch (ptr->correspond)
1357 case DIFF_ALL:
1358 x[0] = 0;
1359 dontprint = 3; /* Print them all */
1360 oddoneout = 3; /* Nobody's odder than anyone else */
1361 break;
1362 case DIFF_1ST:
1363 case DIFF_2ND:
1364 case DIFF_3RD:
1365 oddoneout = rev_mapping[ptr->correspond - DIFF_1ST];
1367 x[0] = oddoneout + '1';
1368 x[1] = 0;
1369 dontprint = oddoneout == 0;
1370 break;
1371 default:
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. */
1377 for (i = 0; i < 3;
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);
1383 long llowt = lowt;
1384 long lhight = hight;
1386 fprintf (outputfile, "%d:", i + 1);
1387 switch (lowt - hight)
1389 case 1:
1390 fprintf (outputfile, "%lda\n", llowt - 1);
1391 break;
1392 case 0:
1393 fprintf (outputfile, "%ldc\n", llowt);
1394 break;
1395 default:
1396 fprintf (outputfile, "%ld,%ldc\n", llowt, lhight);
1397 break;
1400 if (i == dontprint) continue;
1402 if (lowt <= hight)
1404 line = 0;
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.
1426 static bool
1427 dotlines (FILE *outputfile, struct diff3_block *b, int filenum)
1429 lin i;
1430 bool leading_dot = 0;
1432 for (i = 0;
1433 i < D_NUMLINES (b, filenum);
1434 i++)
1436 char *line = D_RELNUM (b, filenum, i);
1437 if (line[0] == '.')
1439 leading_dot = 1;
1440 fprintf (outputfile, ".");
1442 fwrite (line, sizeof (char),
1443 D_RELLEN (b, filenum, i), outputfile);
1446 return leading_dot;
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.)
1455 static void
1456 undotlines (FILE *outputfile, bool leading_dot, long start, lin num)
1458 fprintf (outputfile, ".\n");
1459 if (leading_dot)
1461 if (num == 1)
1462 fprintf (outputfile, "%lds/^\\.//\n", start);
1463 else
1464 fprintf (outputfile, "%ld,%lds/^\\.//\n", start, start + num - 1);
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.
1490 static bool
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)
1495 bool leading_dot;
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. */
1502 enum diff_type type
1503 = (b->correspond == DIFF_ALL
1504 ? DIFF_ALL
1505 : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
1507 long low0, high0;
1509 /* If we aren't supposed to do this output block, skip it. */
1510 switch (type)
1512 default: continue;
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]);
1521 if (conflict)
1523 conflicts_found = 1;
1526 /* Mark end of conflict. */
1528 fprintf (outputfile, "%lda\n", high0);
1529 leading_dot = 0;
1530 if (type == DIFF_ALL)
1532 if (show_2nd)
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);
1552 leading_dot = 0;
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 */
1565 if (low0 == high0)
1566 fprintf (outputfile, "%ldd\n", low0);
1567 else
1568 fprintf (outputfile, "%ld,%ldd\n", low0, high0);
1570 else
1571 /* Write out an add or change */
1573 switch (high0 - low0)
1575 case -1:
1576 fprintf (outputfile, "%lda\n", high0);
1577 break;
1578 case 0:
1579 fprintf (outputfile, "%ldc\n", high0);
1580 break;
1581 default:
1582 fprintf (outputfile, "%ld,%ldc\n", low0, high0);
1583 break;
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.
1606 static bool
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)
1611 int c;
1612 lin i;
1613 bool conflicts_found = 0, conflict;
1614 struct diff3_block *b;
1615 lin linesread = 0;
1617 for (b = diff; b; b = b->next)
1619 /* Must do mapping correctly. */
1620 enum diff_type type
1621 = ((b->correspond == DIFF_ALL)
1622 ? 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. */
1627 switch (type)
1629 default: continue;
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";
1634 break;
1637 /* Copy I lines from file 0. */
1638 i = D_LOWLINE (b, FILE0) - linesread - 1;
1639 linesread += i;
1640 while (0 <= --i)
1643 c = getc (infile);
1644 if (c == EOF)
1646 if (ferror (infile))
1647 perror_with_exit (_("read failed"));
1648 else if (feof (infile))
1649 fatal ("input file shrank");
1651 putc (c, outputfile);
1653 while (c != '\n');
1655 if (conflict)
1657 conflicts_found = 1;
1659 if (type == DIFF_ALL)
1661 /* Put in lines from FILE0 with bracket. */
1662 fprintf (outputfile, "<<<<<<< %s\n", file0);
1663 for (i = 0;
1664 i < D_NUMLINES (b, mapping[FILE0]);
1665 i++)
1666 fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
1667 D_RELLEN (b, mapping[FILE0], i), outputfile);
1670 if (show_2nd)
1672 /* Put in lines from FILE1 with bracket. */
1673 fprintf (outputfile, format_2nd, file1);
1674 for (i = 0;
1675 i < D_NUMLINES (b, mapping[FILE1]);
1676 i++)
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. */
1685 for (i = 0;
1686 i < D_NUMLINES (b, mapping[FILE2]);
1687 i++)
1688 fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
1689 D_RELLEN (b, mapping[FILE2], i), outputfile);
1691 if (conflict)
1692 fprintf (outputfile, ">>>>>>> %s\n", file2);
1694 /* Skip I lines in file 0. */
1695 i = D_NUMLINES (b, FILE0);
1696 linesread += i;
1697 while (0 <= --i)
1698 while ((c = getc (infile)) != '\n')
1699 if (c == EOF)
1701 if (ferror (infile))
1702 perror_with_exit (_("read failed"));
1703 else if (feof (infile))
1705 if (i || b->next)
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)
1727 next = tmp->next;
1728 tmp->next = prev;
1729 prev = tmp;
1732 return prev;
1735 static void
1736 fatal (char const *msgid)
1738 error (EXIT_TROUBLE, 0, "%s", _(msgid));
1739 abort ();
1742 static void
1743 perror_with_exit (char const *string)
1745 error (EXIT_TROUBLE, errno, "%s", string);
1746 abort ();