1 /* diff3 - compare three files line by line
2
3 Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1998, 2001,
4 2002, 2004 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 See the GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; see the file COPYING.
18 If not, write to the Free Software Foundation,
19 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 #include "system.h"
22 #include "paths.h"
23
24 #include <stdio.h>
25 #include <unlocked-io.h>
26
27 #include <c-stack.h>
28 #include <cmpbuf.h>
29 #include <error.h>
30 #include <exitfail.h>
31 #include <file-type.h>
32 #include <getopt.h>
33 #include <inttostr.h>
34 #include <quotesys.h>
35 #include <version-etc.h>
36 #include <xalloc.h>
37
38 /* Internal data structures and macros for the diff3 program; includes
39 data structures for both diff3 diffs and normal diffs. */
40
41 /* Different files within a three way diff. */
42 #define FILE0 0
43 #define FILE1 1
44 #define FILE2 2
45
46 /* A three way diff is built from two two-way diffs; the file which
47 the two two-way diffs share is: */
48 #define FILEC FILE2
49
50 /* Different files within a two way diff.
51 FC is the common file, FO the other file. */
52 #define FO 0
53 #define FC 1
54
55 /* The ranges are indexed by */
56 #define RANGE_START 0
57 #define RANGE_END 1
58
59 enum diff_type {
60 ERROR, /* Should not be used */
61 ADD, /* Two way diff add */
62 CHANGE, /* Two way diff change */
63 DELETE, /* Two way diff delete */
64 DIFF_ALL, /* All three are different */
65 DIFF_1ST, /* Only the first is different */
66 DIFF_2ND, /* Only the second */
67 DIFF_3RD /* Only the third */
68 };
69
70 /* Two way diff */
71 struct diff_block {
72 lin ranges[2][2]; /* Ranges are inclusive */
73 char **lines[2]; /* The actual lines (may contain nulls) */
74 size_t *lengths[2]; /* Line lengths (including newlines, if any) */
75 struct diff_block *next;
76 };
77
78 /* Three way diff */
79
80 struct diff3_block {
81 enum diff_type correspond; /* Type of diff */
82 lin ranges[3][2]; /* Ranges are inclusive */
83 char **lines[3]; /* The actual lines (may contain nulls) */
84 size_t *lengths[3]; /* Line lengths (including newlines, if any) */
85 struct diff3_block *next;
86 };
87
88 /* Access the ranges on a diff block. */
89 #define D_LOWLINE(diff, filenum) \
90 ((diff)->ranges[filenum][RANGE_START])
91 #define D_HIGHLINE(diff, filenum) \
92 ((diff)->ranges[filenum][RANGE_END])
93 #define D_NUMLINES(diff, filenum) \
94 (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
95
96 /* Access the line numbers in a file in a diff by relative line
97 numbers (i.e. line number within the diff itself). Note that these
98 are lvalues and can be used for assignment. */
99 #define D_RELNUM(diff, filenum, linenum) \
100 ((diff)->lines[filenum][linenum])
101 #define D_RELLEN(diff, filenum, linenum) \
102 ((diff)->lengths[filenum][linenum])
103
104 /* And get at them directly, when that should be necessary. */
105 #define D_LINEARRAY(diff, filenum) \
106 ((diff)->lines[filenum])
107 #define D_LENARRAY(diff, filenum) \
108 ((diff)->lengths[filenum])
109
110 /* Next block. */
111 #define D_NEXT(diff) ((diff)->next)
112
113 /* Access the type of a diff3 block. */
114 #define D3_TYPE(diff) ((diff)->correspond)
115
116 /* Line mappings based on diffs. The first maps off the top of the
117 diff, the second off of the bottom. */
118 #define D_HIGH_MAPLINE(diff, fromfile, tofile, linenum) \
119 ((linenum) \
120 - D_HIGHLINE ((diff), (fromfile)) \
121 + D_HIGHLINE ((diff), (tofile)))
122
123 #define D_LOW_MAPLINE(diff, fromfile, tofile, linenum) \
124 ((linenum) \
125 - D_LOWLINE ((diff), (fromfile)) \
126 + D_LOWLINE ((diff), (tofile)))
127
128 /* Options variables for flags set on command line. */
129
130 /* If nonzero, treat all files as text files, never as binary. */
131 static bool text;
132
133 /* Remove trailing carriage returns from input. */
134 static bool strip_trailing_cr;
135
136 /* If nonzero, write out an ed script instead of the standard diff3 format. */
137 static bool edscript;
138
139 /* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
140 preserve the lines which would normally be deleted from
141 file 1 with a special flagging mechanism. */
142 static bool flagging;
143
144 /* Use a tab to align output lines (-T). */
145 static bool initial_tab;
146
147 /* If nonzero, do not output information for overlapping diffs. */
148 static bool simple_only;
149
150 /* If nonzero, do not output information for non-overlapping diffs. */
151 static bool overlap_only;
152
153 /* If nonzero, show information for DIFF_2ND diffs. */
154 static bool show_2nd;
155
156 /* If nonzero, include `:wq' at the end of the script
157 to write out the file being edited. */
158 static bool finalwrite;
159
160 /* If nonzero, output a merged file. */
161 static bool merge;
162
163 char *program_name;
164
165 static char *read_diff (char const *, char const *, char **);
166 static char *scan_diff_line (char *, char **, size_t *, char *, char);
167 static enum diff_type process_diff_control (char **, struct diff_block *);
168 static bool compare_line_list (char * const[], size_t const[], char * const[], size_t const[], lin);
169 static bool copy_stringlist (char * const[], size_t const[], char *[], size_t[], lin);
170 static bool output_diff3_edscript (FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
171 static bool output_diff3_merge (FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);
172 static struct diff3_block *create_diff3_block (lin, lin, lin, lin, lin, lin);
173 static struct diff3_block *make_3way_diff (struct diff_block *, struct diff_block *);
174 static struct diff3_block *reverse_diff3_blocklist (struct diff3_block *);
175 static struct diff3_block *using_to_diff3_block (struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *);
176 static struct diff_block *process_diff (char const *, char const *, struct diff_block **);
177 static void check_stdout (void);
178 static void fatal (char const *) __attribute__((noreturn));
179 static void output_diff3 (FILE *, struct diff3_block *, int const[3], int const[3]);
180 static void perror_with_exit (char const *) __attribute__((noreturn));
181 static void try_help (char const *, char const *) __attribute__((noreturn));
182 static void usage (void);
183
184 static char const *diff_program = DEFAULT_DIFF_PROGRAM;
185
186 /* Values for long options that do not have single-letter equivalents. */
187 enum
188 {
189 DIFF_PROGRAM_OPTION = CHAR_MAX + 1,
190 HELP_OPTION,
191 STRIP_TRAILING_CR_OPTION
192 };
193
194 static struct option const longopts[] =
195 {
196 {"diff-program", 1, 0, DIFF_PROGRAM_OPTION},
197 {"easy-only", 0, 0, '3'},
198 {"ed", 0, 0, 'e'},
199 {"help", 0, 0, HELP_OPTION},
200 {"initial-tab", 0, 0, 'T'},
201 {"label", 1, 0, 'L'},
202 {"merge", 0, 0, 'm'},
203 {"overlap-only", 0, 0, 'x'},
204 {"show-all", 0, 0, 'A'},
205 {"show-overlap", 0, 0, 'E'},
206 {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},
207 {"text", 0, 0, 'a'},
208 {"version", 0, 0, 'v'},
209 {0, 0, 0, 0}
210 };
211
212 int
main(int argc,char ** argv)213 main (int argc, char **argv)
214 {
215 int c, i;
216 int common;
217 int mapping[3];
218 int rev_mapping[3];
219 int incompat = 0;
220 bool conflicts_found;
221 struct diff_block *thread0, *thread1, *last_block;
222 struct diff3_block *diff3;
223 int tag_count = 0;
224 char *tag_strings[3];
225 char *commonname;
226 char **file;
227 struct stat statb;
228
229 exit_failure = 2;
230 initialize_main (&argc, &argv);
231 program_name = argv[0];
232 setlocale (LC_ALL, "");
233 textdomain (PACKAGE);
234 c_stack_action (0);
235
236 while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != -1)
237 {
238 switch (c)
239 {
240 case 'a':
241 text = true;
242 break;
243 case 'A':
244 show_2nd = true;
245 flagging = true;
246 incompat++;
247 break;
248 case 'x':
249 overlap_only = true;
250 incompat++;
251 break;
252 case '3':
253 simple_only = true;
254 incompat++;
255 break;
256 case 'i':
257 finalwrite = true;
258 break;
259 case 'm':
260 merge = true;
261 break;
262 case 'X':
263 overlap_only = true;
264 /* Fall through. */
265 case 'E':
266 flagging = true;
267 /* Fall through. */
268 case 'e':
269 incompat++;
270 break;
271 case 'T':
272 initial_tab = true;
273 break;
274 case STRIP_TRAILING_CR_OPTION:
275 strip_trailing_cr = true;
276 break;
277 case 'v':
278 version_etc (stdout, "diff3", PACKAGE_NAME, PACKAGE_VERSION,
279 "Randy Smith", (char *) 0);
280 check_stdout ();
281 return EXIT_SUCCESS;
282 case DIFF_PROGRAM_OPTION:
283 diff_program = optarg;
284 break;
285 case HELP_OPTION:
286 usage ();
287 check_stdout ();
288 return EXIT_SUCCESS;
289 case 'L':
290 /* Handle up to three -L options. */
291 if (tag_count < 3)
292 {
293 tag_strings[tag_count++] = optarg;
294 break;
295 }
296 try_help ("too many file label options", 0);
297 default:
298 try_help (0, 0);
299 }
300 }
301
302 edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */
303 show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */
304 flagging |= ~incompat & merge;
305
306 if (incompat > 1 /* Ensure at most one of -AeExX3. */
307 || finalwrite & merge /* -i -m would rewrite input file. */
308 || (tag_count && ! flagging)) /* -L requires one of -AEX. */
309 try_help ("incompatible options", 0);
310
311 if (argc - optind != 3)
312 {
313 if (argc - optind < 3)
314 try_help ("missing operand after `%s'", argv[argc - 1]);
315 else
316 try_help ("extra operand `%s'", argv[optind + 3]);
317 }
318
319 file = &argv[optind];
320
321 for (i = tag_count; i < 3; i++)
322 tag_strings[i] = file[i];
323
324 /* Always compare file1 to file2, even if file2 is "-".
325 This is needed for -mAeExX3. Using the file0 as
326 the common file would produce wrong results, because if the
327 file0-file1 diffs didn't line up with the file0-file2 diffs
328 (which is entirely possible since we don't use diff's -n option),
329 diff3 might report phantom changes from file1 to file2.
330
331 Also, try to compare file0 to file1, because this is where
332 changes are expected to come from. Diffing between these pairs
333 of files is more likely to avoid phantom changes from file0 to file1.
334
335 Historically, the default common file was file2, so some older
336 applications (e.g. Emacs ediff) used file2 as the ancestor. So,
337 for compatibility, if this is a 3-way diff (not a merge or
338 edscript), prefer file2 as the common file. */
339
340 common = 2 - (edscript | merge);
341
342 if (strcmp (file[common], "-") == 0)
343 {
344 /* Sigh. We've got standard input as the common file. We can't
345 call diff twice on stdin. Use the other arg as the common
346 file instead. */
347 common = 3 - common;
348 if (strcmp (file[0], "-") == 0 || strcmp (file[common], "-") == 0)
349 fatal ("`-' specified for more than one input file");
350 }
351
352 mapping[0] = 0;
353 mapping[1] = 3 - common;
354 mapping[2] = common;
355
356 for (i = 0; i < 3; i++)
357 rev_mapping[mapping[i]] = i;
358
359 for (i = 0; i < 3; i++)
360 if (strcmp (file[i], "-") != 0)
361 {
362 if (stat (file[i], &statb) < 0)
363 perror_with_exit (file[i]);
364 else if (S_ISDIR (statb.st_mode))
365 error (EXIT_TROUBLE, EISDIR, "%s", file[i]);
366 }
367
368 #ifdef SIGCHLD
369 /* System V fork+wait does not work if SIGCHLD is ignored. */
370 signal (SIGCHLD, SIG_DFL);
371 #endif
372
373 /* Invoke diff twice on two pairs of input files, combine the two
374 diffs, and output them. */
375
376 commonname = file[rev_mapping[FILEC]];
377 thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
378 thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block);
379 diff3 = make_3way_diff (thread0, thread1);
380 if (edscript)
381 conflicts_found
382 = output_diff3_edscript (stdout, diff3, mapping, rev_mapping,
383 tag_strings[0], tag_strings[1], tag_strings[2]);
384 else if (merge)
385 {
386 if (! freopen (file[rev_mapping[FILE0]], "r", stdin))
387 perror_with_exit (file[rev_mapping[FILE0]]);
388 conflicts_found
389 = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping,
390 tag_strings[0], tag_strings[1], tag_strings[2]);
391 if (ferror (stdin))
392 fatal ("read failed");
393 }
394 else
395 {
396 output_diff3 (stdout, diff3, mapping, rev_mapping);
397 conflicts_found = false;
398 }
399
400 check_stdout ();
401 exit (conflicts_found);
402 return conflicts_found;
403 }
404
405 static void
try_help(char const * reason_msgid,char const * operand)406 try_help (char const *reason_msgid, char const *operand)
407 {
408 if (reason_msgid)
409 error (0, 0, _(reason_msgid), operand);
410 error (EXIT_TROUBLE, 0,
411 _("Try `%s --help' for more information."), program_name);
412 abort ();
413 }
414
415 static void
check_stdout(void)416 check_stdout (void)
417 {
418 if (ferror (stdout))
419 fatal ("write failed");
420 else if (fclose (stdout) != 0)
421 perror_with_exit (_("standard output"));
422 }
423
424 static char const * const option_help_msgid[] = {
425 N_("-e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE."),
426 N_("-E --show-overlap Output unmerged changes, bracketing conflicts."),
427 N_("-A --show-all Output all changes, bracketing conflicts."),
428 N_("-x --overlap-only Output overlapping changes."),
429 N_("-X Output overlapping changes, bracketing them."),
430 N_("-3 --easy-only Output unmerged nonoverlapping changes."),
431 "",
432 N_("-m --merge Output merged file instead of ed script (default -A)."),
433 N_("-L LABEL --label=LABEL Use LABEL instead of file name."),
434 N_("-i Append `w' and `q' commands to ed scripts."),
435 N_("-a --text Treat all files as text."),
436 N_("--strip-trailing-cr Strip trailing carriage return on input."),
437 N_("-T --initial-tab Make tabs line up by prepending a tab."),
438 N_("--diff-program=PROGRAM Use PROGRAM to compare files."),
439 "",
440 N_("-v --version Output version info."),
441 N_("--help Output this help."),
442 0
443 };
444
445 static void
usage(void)446 usage (void)
447 {
448 char const * const *p;
449
450 printf (_("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n"),
451 program_name);
452 printf ("%s\n\n", _("Compare three files line by line."));
453 for (p = option_help_msgid; *p; p++)
454 if (**p)
455 printf (" %s\n", _(*p));
456 else
457 putchar ('\n');
458 printf ("\n%s\n%s\n\n%s\n",
459 _("If a FILE is `-', read standard input."),
460 _("Exit status is 0 if successful, 1 if conflicts, 2 if trouble."),
461 _("Report bugs to <bug-gnu-utils@gnu.org>."));
462 }
463
464 /* Combine the two diffs together into one.
465 Here is the algorithm:
466
467 File2 is shared in common between the two diffs.
468 Diff02 is the diff between 0 and 2.
469 Diff12 is the diff between 1 and 2.
470
471 1) Find the range for the first block in File2.
472 a) Take the lowest of the two ranges (in File2) in the two
473 current blocks (one from each diff) as being the low
474 water mark. Assign the upper end of this block as
475 being the high water mark and move the current block up
476 one. Mark the block just moved over as to be used.
477 b) Check the next block in the diff that the high water
478 mark is *not* from.
479
480 *If* the high water mark is above
481 the low end of the range in that block,
482
483 mark that block as to be used and move the current
484 block up. Set the high water mark to the max of
485 the high end of this block and the current. Repeat b.
486
487 2) Find the corresponding ranges in File0 (from the blocks
488 in diff02; line per line outside of diffs) and in File1.
489 Create a diff3_block, reserving space as indicated by the ranges.
490
491 3) Copy all of the pointers for file2 in. At least for now,
492 do memcmp's between corresponding strings in the two diffs.
493
494 4) Copy all of the pointers for file0 and 1 in. Get what is
495 needed from file2 (when there isn't a diff block, it's
496 identical to file2 within the range between diff blocks).
497
498 5) If the diff blocks used came from only one of the two
499 strings of diffs, then that file (i.e. the one other than
500 the common file in that diff) is the odd person out. If
501 diff blocks are used from both sets, check to see if files
502 0 and 1 match:
503
504 Same number of lines? If so, do a set of memcmp's (if
505 a memcmp matches; copy the pointer over; it'll be easier
506 later during comparisons). If they match, 0 & 1 are the
507 same. If not, all three different.
508
509 Then do it again, until the blocks are exhausted. */
510
511
512 /* Make a three way diff (chain of diff3_block's) from two two way
513 diffs (chains of diff_block's). Assume that each of the two diffs
514 passed are onto the same file (i.e. that each of the diffs were
515 made "to" the same file). Return a three way diff pointer with
516 numbering FILE0 = the other file in diff02, FILE1 = the other file
517 in diff12, and FILEC = the common file. */
518
519 static struct diff3_block *
make_3way_diff(struct diff_block * thread0,struct diff_block * thread1)520 make_3way_diff (struct diff_block *thread0, struct diff_block *thread1)
521 {
522 /* Work on the two diffs passed to it as threads. Thread number 0
523 is diff02, thread number 1 is diff12. USING is the base of the
524 list of blocks to be used to construct each block of the three
525 way diff; if no blocks from a particular thread are to be used,
526 that element of USING is 0. LAST_USING contains the last
527 elements on each of the using lists.
528
529 HIGH_WATER_MARK is the highest line number in the common file
530 described in any of the diffs in either of the USING lists.
531 HIGH_WATER_THREAD names the thread. Similarly BASE_WATER_MARK
532 and BASE_WATER_THREAD describe the lowest line number in the
533 common file described in any of the diffs in either of the USING
534 lists. HIGH_WATER_DIFF is the diff from which the
535 HIGH_WATER_MARK was taken.
536
537 HIGH_WATER_DIFF should always be equal to
538 LAST_USING[HIGH_WATER_THREAD]. OTHER_DIFF is the next diff to
539 check for higher water, and should always be equal to
540 CURRENT[HIGH_WATER_THREAD ^ 1]. OTHER_THREAD is the thread in
541 which the OTHER_DIFF is, and hence should always be equal to
542 HIGH_WATER_THREAD ^ 1.
543
544 LAST_DIFF is the last diff block produced by this routine, for
545 line correspondence purposes between that diff and the one
546 currently being worked on. It is ZERO_DIFF before any blocks
547 have been created. */
548
549 struct diff_block *using[2];
550 struct diff_block *last_using[2];
551 struct diff_block *current[2];
552
553 lin high_water_mark;
554
555 int high_water_thread;
556 int base_water_thread;
557 int other_thread;
558
559 struct diff_block *high_water_diff;
560 struct diff_block *other_diff;
561
562 struct diff3_block *result;
563 struct diff3_block *tmpblock;
564 struct diff3_block **result_end;
565
566 struct diff3_block const *last_diff3;
567
568 static struct diff3_block const zero_diff3;
569
570 /* Initialization */
571 result = 0;
572 result_end = &result;
573 current[0] = thread0; current[1] = thread1;
574 last_diff3 = &zero_diff3;
575
576 /* Sniff up the threads until we reach the end */
577
578 while (current[0] || current[1])
579 {
580 using[0] = using[1] = last_using[0] = last_using[1] = 0;
581
582 /* Setup low and high water threads, diffs, and marks. */
583 if (!current[0])
584 base_water_thread = 1;
585 else if (!current[1])
586 base_water_thread = 0;
587 else
588 base_water_thread =
589 (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
590
591 high_water_thread = base_water_thread;
592
593 high_water_diff = current[high_water_thread];
594
595 high_water_mark = D_HIGHLINE (high_water_diff, FC);
596
597 /* Make the diff you just got info from into the using class */
598 using[high_water_thread]
599 = last_using[high_water_thread]
600 = high_water_diff;
601 current[high_water_thread] = high_water_diff->next;
602 last_using[high_water_thread]->next = 0;
603
604 /* And mark the other diff */
605 other_thread = high_water_thread ^ 0x1;
606 other_diff = current[other_thread];
607
608 /* Shuffle up the ladder, checking the other diff to see if it
609 needs to be incorporated. */
610 while (other_diff
611 && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
612 {
613
614 /* Incorporate this diff into the using list. Note that
615 this doesn't take it off the current list */
616 if (using[other_thread])
617 last_using[other_thread]->next = other_diff;
618 else
619 using[other_thread] = other_diff;
620 last_using[other_thread] = other_diff;
621
622 /* Take it off the current list. Note that this following
623 code assumes that other_diff enters it equal to
624 current[high_water_thread ^ 0x1] */
625 current[other_thread] = current[other_thread]->next;
626 other_diff->next = 0;
627
628 /* Set the high_water stuff
629 If this comparison is equal, then this is the last pass
630 through this loop; since diff blocks within a given
631 thread cannot overlap, the high_water_mark will be
632 *below* the range_start of either of the next diffs. */
633
634 if (high_water_mark < D_HIGHLINE (other_diff, FC))
635 {
636 high_water_thread ^= 1;
637 high_water_diff = other_diff;
638 high_water_mark = D_HIGHLINE (other_diff, FC);
639 }
640
641 /* Set the other diff */
642 other_thread = high_water_thread ^ 0x1;
643 other_diff = current[other_thread];
644 }
645
646 /* The using lists contain a list of all of the blocks to be
647 included in this diff3_block. Create it. */
648
649 tmpblock = using_to_diff3_block (using, last_using,
650 base_water_thread, high_water_thread,
651 last_diff3);
652
653 if (!tmpblock)
654 fatal ("internal error: screwup in format of diff blocks");
655
656 /* Put it on the list. */
657 *result_end = tmpblock;
658 result_end = &tmpblock->next;
659
660 /* Set up corresponding lines correctly. */
661 last_diff3 = tmpblock;
662 }
663 return result;
664 }
665
666 /* Take two lists of blocks (from two separate diff threads) and put
667 them together into one diff3 block. Return a pointer to this diff3
668 block or 0 for failure.
669
670 All arguments besides using are for the convenience of the routine;
671 they could be derived from the using array. LAST_USING is a pair
672 of pointers to the last blocks in the using structure. LOW_THREAD
673 and HIGH_THREAD tell which threads contain the lowest and highest
674 line numbers for File0. LAST_DIFF3 contains the last diff produced
675 in the calling routine. This is used for lines mappings that
676 would still be identical to the state that diff ended in.
677
678 A distinction should be made in this routine between the two diffs
679 that are part of a normal two diff block, and the three diffs that
680 are part of a diff3_block. */
681
682 static struct diff3_block *
using_to_diff3_block(struct diff_block * using[2],struct diff_block * last_using[2],int low_thread,int high_thread,struct diff3_block const * last_diff3)683 using_to_diff3_block (struct diff_block *using[2],
684 struct diff_block *last_using[2],
685 int low_thread, int high_thread,
686 struct diff3_block const *last_diff3)
687 {
688 lin low[2], high[2];
689 struct diff3_block *result;
690 struct diff_block *ptr;
691 int d;
692 lin i;
693
694 /* Find the range in the common file. */
695 lin lowc = D_LOWLINE (using[low_thread], FC);
696 lin highc = D_HIGHLINE (last_using[high_thread], FC);
697
698 /* Find the ranges in the other files.
699 If using[d] is null, that means that the file to which that diff
700 refers is equivalent to the common file over this range. */
701
702 for (d = 0; d < 2; d++)
703 if (using[d])
704 {
705 low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
706 high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
707 }
708 else
709 {
710 low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
711 high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
712 }
713
714 /* Create a block with the appropriate sizes */
715 result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
716
717 /* Copy information for the common file.
718 Return with a zero if any of the compares failed. */
719
720 for (d = 0; d < 2; d++)
721 for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
722 {
723 lin result_offset = D_LOWLINE (ptr, FC) - lowc;
724
725 if (!copy_stringlist (D_LINEARRAY (ptr, FC),
726 D_LENARRAY (ptr, FC),
727 D_LINEARRAY (result, FILEC) + result_offset,
728 D_LENARRAY (result, FILEC) + result_offset,
729 D_NUMLINES (ptr, FC)))
730 return 0;
731 }
732
733 /* Copy information for file d. First deal with anything that might be
734 before the first diff. */
735
736 for (d = 0; d < 2; d++)
737 {
738 struct diff_block *u = using[d];
739 lin lo = low[d], hi = high[d];
740
741 for (i = 0;
742 i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
743 i++)
744 {
745 D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
746 D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
747 }
748
749 for (ptr = u; ptr; ptr = D_NEXT (ptr))
750 {
751 lin result_offset = D_LOWLINE (ptr, FO) - lo;
752 lin linec;
753
754 if (!copy_stringlist (D_LINEARRAY (ptr, FO),
755 D_LENARRAY (ptr, FO),
756 D_LINEARRAY (result, FILE0 + d) + result_offset,
757 D_LENARRAY (result, FILE0 + d) + result_offset,
758 D_NUMLINES (ptr, FO)))
759 return 0;
760
761 /* Catch the lines between here and the next diff */
762 linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
763 for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
764 i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
765 i++)
766 {
767 D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
768 D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
769 linec++;
770 }
771 }
772 }
773
774 /* Set correspond */
775 if (!using[0])
776 D3_TYPE (result) = DIFF_2ND;
777 else if (!using[1])
778 D3_TYPE (result) = DIFF_1ST;
779 else
780 {
781 lin nl0 = D_NUMLINES (result, FILE0);
782 lin nl1 = D_NUMLINES (result, FILE1);
783
784 if (nl0 != nl1
785 || !compare_line_list (D_LINEARRAY (result, FILE0),
786 D_LENARRAY (result, FILE0),
787 D_LINEARRAY (result, FILE1),
788 D_LENARRAY (result, FILE1),
789 nl0))
790 D3_TYPE (result) = DIFF_ALL;
791 else
792 D3_TYPE (result) = DIFF_3RD;
793 }
794
795 return result;
796 }
797
798 /* Copy pointers from a list of strings to a different list of
799 strings. If a spot in the second list is already filled, make sure
800 that it is filled with the same string; if not, return false, the copy
801 incomplete. Upon successful completion of the copy, return true. */
802
803 static bool
copy_stringlist(char * const fromptrs[],size_t const fromlengths[],char * toptrs[],size_t tolengths[],lin copynum)804 copy_stringlist (char * const fromptrs[], size_t const fromlengths[],
805 char *toptrs[], size_t tolengths[],
806 lin copynum)
807 {
808 register char * const *f = fromptrs;
809 register char **t = toptrs;
810 register size_t const *fl = fromlengths;
811 register size_t *tl = tolengths;
812
813 while (copynum--)
814 {
815 if (*t)
816 {
817 if (*fl != *tl || memcmp (*f, *t, *fl) != 0)
818 return false;
819 }
820 else
821 {
822 *t = *f;
823 *tl = *fl;
824 }
825
826 t++; f++; tl++; fl++;
827 }
828
829 return true;
830 }
831
832 /* Create a diff3_block, with ranges as specified in the arguments.
833 Allocate the arrays for the various pointers (and zero them) based
834 on the arguments passed. Return the block as a result. */
835
836 static struct diff3_block *
create_diff3_block(lin low0,lin high0,lin low1,lin high1,lin low2,lin high2)837 create_diff3_block (lin low0, lin high0,
838 lin low1, lin high1,
839 lin low2, lin high2)
840 {
841 struct diff3_block *result = xmalloc (sizeof *result);
842 lin numlines;
843
844 D3_TYPE (result) = ERROR;
845 D_NEXT (result) = 0;
846
847 /* Assign ranges */
848 D_LOWLINE (result, FILE0) = low0;
849 D_HIGHLINE (result, FILE0) = high0;
850 D_LOWLINE (result, FILE1) = low1;
851 D_HIGHLINE (result, FILE1) = high1;
852 D_LOWLINE (result, FILE2) = low2;
853 D_HIGHLINE (result, FILE2) = high2;
854
855 /* Allocate and zero space */
856 numlines = D_NUMLINES (result, FILE0);
857 if (numlines)
858 {
859 D_LINEARRAY (result, FILE0) = xcalloc (numlines, sizeof (char *));
860 D_LENARRAY (result, FILE0) = xcalloc (numlines, sizeof (size_t));
861 }
862 else
863 {
864 D_LINEARRAY (result, FILE0) = 0;
865 D_LENARRAY (result, FILE0) = 0;
866 }
867
868 numlines = D_NUMLINES (result, FILE1);
869 if (numlines)
870 {
871 D_LINEARRAY (result, FILE1) = xcalloc (numlines, sizeof (char *));
872 D_LENARRAY (result, FILE1) = xcalloc (numlines, sizeof (size_t));
873 }
874 else
875 {
876 D_LINEARRAY (result, FILE1) = 0;
877 D_LENARRAY (result, FILE1) = 0;
878 }
879
880 numlines = D_NUMLINES (result, FILE2);
881 if (numlines)
882 {
883 D_LINEARRAY (result, FILE2) = xcalloc (numlines, sizeof (char *));
884 D_LENARRAY (result, FILE2) = xcalloc (numlines, sizeof (size_t));
885 }
886 else
887 {
888 D_LINEARRAY (result, FILE2) = 0;
889 D_LENARRAY (result, FILE2) = 0;
890 }
891
892 /* Return */
893 return result;
894 }
895
896 /* Compare two lists of lines of text.
897 Return 1 if they are equivalent, 0 if not. */
898
899 static bool
compare_line_list(char * const list1[],size_t const lengths1[],char * const list2[],size_t const lengths2[],lin nl)900 compare_line_list (char * const list1[], size_t const lengths1[],
901 char * const list2[], size_t const lengths2[],
902 lin nl)
903 {
904 char * const *l1 = list1;
905 char * const *l2 = list2;
906 size_t const *lgths1 = lengths1;
907 size_t const *lgths2 = lengths2;
908
909 while (nl--)
910 if (!*l1 || !*l2 || *lgths1 != *lgths2++
911 || memcmp (*l1++, *l2++, *lgths1++) != 0)
912 return false;
913 return true;
914 }
915
916 /* Input and parse two way diffs. */
917
918 static struct diff_block *
process_diff(char const * filea,char const * fileb,struct diff_block ** last_block)919 process_diff (char const *filea,
920 char const *fileb,
921 struct diff_block **last_block)
922 {
923 char *diff_contents;
924 char *diff_limit;
925 char *scan_diff;
926 enum diff_type dt;
927 lin i;
928 struct diff_block *block_list, **block_list_end, *bptr;
929 size_t too_many_lines = (PTRDIFF_MAX
930 / MIN (sizeof *bptr->lines[1],
931 sizeof *bptr->lengths[1]));
932
933 diff_limit = read_diff (filea, fileb, &diff_contents);
934 scan_diff = diff_contents;
935 block_list_end = &block_list;
936 bptr = 0; /* Pacify `gcc -W'. */
937
938 while (scan_diff < diff_limit)
939 {
940 bptr = xmalloc (sizeof *bptr);
941 bptr->lines[0] = bptr->lines[1] = 0;
942 bptr->lengths[0] = bptr->lengths[1] = 0;
943
944 dt = process_diff_control (&scan_diff, bptr);
945 if (dt == ERROR || *scan_diff != '\n')
946 {
947 fprintf (stderr, _("%s: diff failed: "), program_name);
948 do
949 {
950 putc (*scan_diff, stderr);
951 }
952 while (*scan_diff++ != '\n');
953 exit (EXIT_TROUBLE);
954 }
955 scan_diff++;
956
957 /* Force appropriate ranges to be null, if necessary */
958 switch (dt)
959 {
960 case ADD:
961 bptr->ranges[0][0]++;
962 break;
963 case DELETE:
964 bptr->ranges[1][0]++;
965 break;
966 case CHANGE:
967 break;
968 default:
969 fatal ("internal error: invalid diff type in process_diff");
970 break;
971 }
972
973 /* Allocate space for the pointers for the lines from filea, and
974 parcel them out among these pointers */
975 if (dt != ADD)
976 {
977 lin numlines = D_NUMLINES (bptr, 0);
978 if (too_many_lines <= numlines)
979 xalloc_die ();
980 bptr->lines[0] = xmalloc (numlines * sizeof *bptr->lines[0]);
981 bptr->lengths[0] = xmalloc (numlines * sizeof *bptr->lengths[0]);
982 for (i = 0; i < numlines; i++)
983 scan_diff = scan_diff_line (scan_diff,
984 &(bptr->lines[0][i]),
985 &(bptr->lengths[0][i]),
986 diff_limit,
987 '<');
988 }
989
990 /* Get past the separator for changes */
991 if (dt == CHANGE)
992 {
993 if (strncmp (scan_diff, "---\n", 4))
994 fatal ("invalid diff format; invalid change separator");
995 scan_diff += 4;
996 }
997
998 /* Allocate space for the pointers for the lines from fileb, and
999 parcel them out among these pointers */
1000 if (dt != DELETE)
1001 {
1002 lin numlines = D_NUMLINES (bptr, 1);
1003 if (too_many_lines <= numlines)
1004 xalloc_die ();
1005 bptr->lines[1] = xmalloc (numlines * sizeof *bptr->lines[1]);
1006 bptr->lengths[1] = xmalloc (numlines * sizeof *bptr->lengths[1]);
1007 for (i = 0; i < numlines; i++)
1008 scan_diff = scan_diff_line (scan_diff,
1009 &(bptr->lines[1][i]),
1010 &(bptr->lengths[1][i]),
1011 diff_limit,
1012 '>');
1013 }
1014
1015 /* Place this block on the blocklist. */
1016 *block_list_end = bptr;
1017 block_list_end = &bptr->next;
1018 }
1019
1020 *block_list_end = 0;
1021 *last_block = bptr;
1022 return block_list;
1023 }
1024
1025 /* Skip tabs and spaces, and return the first character after them. */
1026
1027 static char *
skipwhite(char * s)1028 skipwhite (char *s)
1029 {
1030 while (*s == ' ' || *s == '\t')
1031 s++;
1032 return s;
1033 }
1034
1035 /* Read a nonnegative line number from S, returning the address of the
1036 first character after the line number, and storing the number into
1037 *PNUM. Return 0 if S does not point to a valid line number. */
1038
1039 static char *
readnum(char * s,lin * pnum)1040 readnum (char *s, lin *pnum)
1041 {
1042 unsigned char c = *s;
1043 lin num = 0;
1044
1045 if (! ISDIGIT (c))
1046 return 0;
1047
1048 do
1049 {
1050 num = c - '0' + num * 10;
1051 c = *++s;
1052 }
1053 while (ISDIGIT (c));
1054
1055 *pnum = num;
1056 return s;
1057 }
1058
1059 /* Parse a normal format diff control string. Return the type of the
1060 diff (ERROR if the format is bad). All of the other important
1061 information is filled into to the structure pointed to by db, and
1062 the string pointer (whose location is passed to this routine) is
1063 updated to point beyond the end of the string parsed. Note that
1064 only the ranges in the diff_block will be set by this routine.
1065
1066 If some specific pair of numbers has been reduced to a single
1067 number, then both corresponding numbers in the diff block are set
1068 to that number. In general these numbers are interpreted as ranges
1069 inclusive, unless being used by the ADD or DELETE commands. It is
1070 assumed that these will be special cased in a superior routine. */
1071
1072 static enum diff_type
process_diff_control(char ** string,struct diff_block * db)1073 process_diff_control (char **string, struct diff_block *db)
1074 {
1075 char *s = *string;
1076 enum diff_type type;
1077
1078 /* Read first set of digits */
1079 s = readnum (skipwhite (s), &db->ranges[0][RANGE_START]);
1080 if (! s)
1081 return ERROR;
1082
1083 /* Was that the only digit? */
1084 s = skipwhite (s);
1085 if (*s == ',')
1086 {
1087 s = readnum (s + 1, &db->ranges[0][RANGE_END]);
1088 if (! s)
1089 return ERROR;
1090 }
1091 else
1092 db->ranges[0][RANGE_END] = db->ranges[0][RANGE_START];
1093
1094 /* Get the letter */
1095 s = skipwhite (s);
1096 switch (*s)
1097 {
1098 case 'a':
1099 type = ADD;
1100 break;
1101 case 'c':
1102 type = CHANGE;
1103 break;
1104 case 'd':
1105 type = DELETE;
1106 break;
1107 default:
1108 return ERROR; /* Bad format */
1109 }
1110 s++; /* Past letter */
1111
1112 /* Read second set of digits */
1113 s = readnum (skipwhite (s), &db->ranges[1][RANGE_START]);
1114 if (! s)
1115 return ERROR;
1116
1117 /* Was that the only digit? */
1118 s = skipwhite (s);
1119 if (*s == ',')
1120 {
1121 s = readnum (s + 1, &db->ranges[1][RANGE_END]);
1122 if (! s)
1123 return ERROR;
1124 s = skipwhite (s); /* To move to end */
1125 }
1126 else
1127 db->ranges[1][RANGE_END] = db->ranges[1][RANGE_START];
1128
1129 *string = s;
1130 return type;
1131 }
1132
1133 static char *
read_diff(char const * filea,char const * fileb,char ** output_placement)1134 read_diff (char const *filea,
1135 char const *fileb,
1136 char **output_placement)
1137 {
1138 char *diff_result;
1139 size_t current_chunk_size, total;
1140 int fd, wstatus, status;
1141 int werrno = 0;
1142 struct stat pipestat;
1143
1144 #if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
1145
1146 char const *argv[9];
1147 char const **ap;
1148 int fds[2];
1149 pid_t pid;
1150
1151 ap = argv;
1152 *ap++ = diff_program;
1153 if (text)
1154 *ap++ = "-a";
1155 if (strip_trailing_cr)
1156 *ap++ = "--strip-trailing-cr";
1157 *ap++ = "--horizon-lines=100";
1158 *ap++ = "--";
1159 *ap++ = filea;
1160 *ap++ = fileb;
1161 *ap = 0;
1162
1163 if (pipe (fds) != 0)
1164 perror_with_exit ("pipe");
1165
1166 pid = vfork ();
1167 if (pid == 0)
1168 {
1169 /* Child */
1170 close (fds[0]);
1171 if (fds[1] != STDOUT_FILENO)
1172 {
1173 dup2 (fds[1], STDOUT_FILENO);
1174 close (fds[1]);
1175 }
1176
1177 /* The cast to (char **) is needed for portability to older
1178 hosts with a nonstandard prototype for execvp. */
1179 execvp (diff_program, (char **) argv);
1180
1181 _exit (errno == ENOENT ? 127 : 126);
1182 }
1183
1184 if (pid == -1)
1185 perror_with_exit ("fork");
1186
1187 close (fds[1]); /* Prevent erroneous lack of EOF */
1188 fd = fds[0];
1189
1190 #else
1191
1192 FILE *fpipe;
1193 char const args[] = " --horizon-lines=100 -- ";
1194 char *command = xmalloc (quote_system_arg (0, diff_program)
1195 + sizeof "-a"
1196 + sizeof "--strip-trailing-cr"
1197 + sizeof args - 1
1198 + quote_system_arg (0, filea) + 1
1199 + quote_system_arg (0, fileb) + 1);
1200 char *p = command;
1201 p += quote_system_arg (p, diff_program);
1202 if (text)
1203 {
1204 strcpy (p, " -a");
1205 p += 3;
1206 }
1207 if (strip_trailing_cr)
1208 {
1209 strcpy (p, " --strip-trailing-cr");
1210 p += 20;
1211 }
1212 strcpy (p, args);
1213 p += sizeof args - 1;
1214 p += quote_system_arg (p, filea);
1215 *p++ = ' ';
1216 p += quote_system_arg (p, fileb);
1217 *p = 0;
1218 errno = 0;
1219 fpipe = popen (command, "r");
1220 if (!fpipe)
1221 perror_with_exit (command);
1222 free (command);
1223 fd = fileno (fpipe);
1224
1225 #endif
1226
1227 if (fstat (fd, &pipestat) != 0)
1228 perror_with_exit ("fstat");
1229 current_chunk_size = MAX (1, STAT_BLOCKSIZE (pipestat));
1230 diff_result = xmalloc (current_chunk_size);
1231 total = 0;
1232
1233 for (;;)
1234 {
1235 size_t bytes_to_read = current_chunk_size - total;
1236 size_t bytes = block_read (fd, diff_result + total, bytes_to_read);
1237 total += bytes;
1238 if (bytes != bytes_to_read)
1239 {
1240 if (bytes == SIZE_MAX)
1241 perror_with_exit (_("read failed"));
1242 break;
1243 }
1244 if (PTRDIFF_MAX / 2 <= current_chunk_size)
1245 xalloc_die ();
1246 current_chunk_size *= 2;
1247 diff_result = xrealloc (diff_result, current_chunk_size);
1248 }
1249
1250 if (total != 0 && diff_result[total-1] != '\n')
1251 fatal ("invalid diff format; incomplete last line");
1252
1253 *output_placement = diff_result;
1254
1255 #if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
1256
1257 wstatus = pclose (fpipe);
1258 if (wstatus == -1)
1259 werrno = errno;
1260
1261 #else
1262
1263 if (close (fd) != 0)
1264 perror_with_exit ("close");
1265 if (waitpid (pid, &wstatus, 0) < 0)
1266 perror_with_exit ("waitpid");
1267
1268 #endif
1269
1270 status = ! werrno && WIFEXITED (wstatus) ? WEXITSTATUS (wstatus) : INT_MAX;
1271
1272 if (EXIT_TROUBLE <= status)
1273 error (EXIT_TROUBLE, werrno,
1274 _(status == 126
1275 ? "subsidiary program `%s' could not be invoked"
1276 : status == 127
1277 ? "subsidiary program `%s' not found"
1278 : status == INT_MAX
1279 ? "subsidiary program `%s' failed"
1280 : "subsidiary program `%s' failed (exit status %d)"),
1281 diff_program, status);
1282
1283 return diff_result + total;
1284 }
1285
1286
1287 /* Scan a regular diff line (consisting of > or <, followed by a
1288 space, followed by text (including nulls) up to a newline.
1289
1290 This next routine began life as a macro and many parameters in it
1291 are used as call-by-reference values. */
1292 static char *
scan_diff_line(char * scan_ptr,char ** set_start,size_t * set_length,char * limit,char leadingchar)1293 scan_diff_line (char *scan_ptr, char **set_start, size_t *set_length,
1294 char *limit, char leadingchar)
1295 {
1296 char *line_ptr;
1297
1298 if (!(scan_ptr[0] == leadingchar
1299 && scan_ptr[1] == ' '))
1300 fatal ("invalid diff format; incorrect leading line chars");
1301
1302 *set_start = line_ptr = scan_ptr + 2;
1303 while (*line_ptr++ != '\n')
1304 continue;
1305
1306 /* Include newline if the original line ended in a newline,
1307 or if an edit script is being generated.
1308 Copy any missing newline message to stderr if an edit script is being
1309 generated, because edit scripts cannot handle missing newlines.
1310 Return the beginning of the next line. */
1311 *set_length = line_ptr - *set_start;
1312 if (line_ptr < limit && *line_ptr == '\\')
1313 {
1314 if (edscript)
1315 fprintf (stderr, "%s:", program_name);
1316 else
1317 --*set_length;
1318 line_ptr++;
1319 do
1320 {
1321 if (edscript)
1322 putc (*line_ptr, stderr);
1323 }
1324 while (*line_ptr++ != '\n');
1325 }
1326
1327 return line_ptr;
1328 }
1329
1330 /* Output a three way diff passed as a list of diff3_block's. The
1331 argument MAPPING is indexed by external file number (in the
1332 argument list) and contains the internal file number (from the diff
1333 passed). This is important because the user expects outputs in
1334 terms of the argument list number, and the diff passed may have
1335 been done slightly differently (if the last argument was "-", for
1336 example). REV_MAPPING is the inverse of MAPPING. */
1337
1338 static void
output_diff3(FILE * outputfile,struct diff3_block * diff,int const mapping[3],int const rev_mapping[3])1339 output_diff3 (FILE *outputfile, struct diff3_block *diff,
1340 int const mapping[3], int const rev_mapping[3])
1341 {
1342 int i;
1343 int oddoneout;
1344 char *cp;
1345 struct diff3_block *ptr;
1346 lin line;
1347 size_t length;
1348 int dontprint;
1349 static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
1350 char const *line_prefix = initial_tab ? "\t" : " ";
1351
1352 for (ptr = diff; ptr; ptr = D_NEXT (ptr))
1353 {
1354 char x[2];
1355
1356 switch (ptr->correspond)
1357 {
1358 case DIFF_ALL:
1359 x[0] = 0;
1360 dontprint = 3; /* Print them all */
1361 oddoneout = 3; /* Nobody's odder than anyone else */
1362 break;
1363 case DIFF_1ST:
1364 case DIFF_2ND:
1365 case DIFF_3RD:
1366 oddoneout = rev_mapping[ptr->correspond - DIFF_1ST];
1367
1368 x[0] = oddoneout + '1';
1369 x[1] = 0;
1370 dontprint = oddoneout == 0;
1371 break;
1372 default:
1373 fatal ("internal error: invalid diff type passed to output");
1374 }
1375 fprintf (outputfile, "====%s\n", x);
1376
1377 /* Go 0, 2, 1 if the first and third outputs are equivalent. */
1378 for (i = 0; i < 3;
1379 i = (oddoneout == 1 ? skew_increment[i] : i + 1))
1380 {
1381 int realfile = mapping[i];
1382 lin lowt = D_LOWLINE (ptr, realfile);
1383 lin hight = D_HIGHLINE (ptr, realfile);
1384 long int llowt = lowt;
1385 long int lhight = hight;
1386
1387 fprintf (outputfile, "%d:", i + 1);
1388 switch (lowt - hight)
1389 {
1390 case 1:
1391 fprintf (outputfile, "%lda\n", llowt - 1);
1392 break;
1393 case 0:
1394 fprintf (outputfile, "%ldc\n", llowt);
1395 break;
1396 default:
1397 fprintf (outputfile, "%ld,%ldc\n", llowt, lhight);
1398 break;
1399 }
1400
1401 if (i == dontprint) continue;
1402
1403 if (lowt <= hight)
1404 {
1405 line = 0;
1406 do
1407 {
1408 fprintf (outputfile, line_prefix);
1409 cp = D_RELNUM (ptr, realfile, line);
1410 length = D_RELLEN (ptr, realfile, line);
1411 fwrite (cp, sizeof (char), length, outputfile);
1412 }
1413 while (++line < hight - lowt + 1);
1414 if (cp[length - 1] != '\n')
1415 fprintf (outputfile, "\n\\ %s\n",
1416 _("No newline at end of file"));
1417 }
1418 }
1419 }
1420 }
1421
1422
1423 /* Output to OUTPUTFILE the lines of B taken from FILENUM. Double any
1424 initial '.'s; yield nonzero if any initial '.'s were doubled. */
1425
1426 static bool
dotlines(FILE * outputfile,struct diff3_block * b,int filenum)1427 dotlines (FILE *outputfile, struct diff3_block *b, int filenum)
1428 {
1429 lin i;
1430 bool leading_dot = false;
1431
1432 for (i = 0;
1433 i < D_NUMLINES (b, filenum);
1434 i++)
1435 {
1436 char *line = D_RELNUM (b, filenum, i);
1437 if (line[0] == '.')
1438 {
1439 leading_dot = true;
1440 fprintf (outputfile, ".");
1441 }
1442 fwrite (line, sizeof (char),
1443 D_RELLEN (b, filenum, i), outputfile);
1444 }
1445
1446 return leading_dot;
1447 }
1448
1449 /* Output to OUTPUTFILE a '.' line. If LEADING_DOT is true, also
1450 output a command that removes initial '.'s starting with line START
1451 and continuing for NUM lines. (START is long int, not lin, for
1452 convenience with printf %ld formats.) */
1453
1454 static void
undotlines(FILE * outputfile,bool leading_dot,long int start,lin num)1455 undotlines (FILE *outputfile, bool leading_dot, long int start, lin num)
1456 {
1457 fprintf (outputfile, ".\n");
1458 if (leading_dot)
1459 {
1460 if (num == 1)
1461 fprintf (outputfile, "%lds/^\\.//\n", start);
1462 else
1463 fprintf (outputfile, "%ld,%lds/^\\.//\n", start, start + num - 1);
1464 }
1465 }
1466
1467 /* Output a diff3 set of blocks as an ed script. This script applies
1468 the changes between file's 2 & 3 to file 1. Take the precise
1469 format of the ed script to be output from global variables set
1470 during options processing. Reverse the order of
1471 the set of diff3 blocks in DIFF; this gets
1472 around the problems involved with changing line numbers in an ed
1473 script.
1474
1475 As in `output_diff3', the variable MAPPING maps from file number
1476 according to the argument list to file number according to the diff
1477 passed. All files listed below are in terms of the argument list.
1478 REV_MAPPING is the inverse of MAPPING.
1479
1480 FILE0, FILE1 and FILE2 are the strings to print as the names of the
1481 three files. These may be the actual names, or may be the
1482 arguments specified with -L.
1483
1484 Return 1 if conflicts were found. */
1485
1486 static bool
output_diff3_edscript(FILE * outputfile,struct diff3_block * diff,int const mapping[3],int const rev_mapping[3],char const * file0,char const * file1,char const * file2)1487 output_diff3_edscript (FILE *outputfile, struct diff3_block *diff,
1488 int const mapping[3], int const rev_mapping[3],
1489 char const *file0, char const *file1, char const *file2)
1490 {
1491 bool leading_dot;
1492 bool conflicts_found = false;
1493 bool conflict;
1494 struct diff3_block *b;
1495
1496 for (b = reverse_diff3_blocklist (diff); b; b = b->next)
1497 {
1498 /* Must do mapping correctly. */
1499 enum diff_type type
1500 = (b->correspond == DIFF_ALL
1501 ? DIFF_ALL
1502 : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
1503
1504 long int low0, high0;
1505
1506 /* If we aren't supposed to do this output block, skip it. */
1507 switch (type)
1508 {
1509 default: continue;
1510 case DIFF_2ND: if (!show_2nd) continue; conflict = true; break;
1511 case DIFF_3RD: if (overlap_only) continue; conflict = false; break;
1512 case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
1513 }
1514
1515 low0 = D_LOWLINE (b, mapping[FILE0]);
1516 high0 = D_HIGHLINE (b, mapping[FILE0]);
1517
1518 if (conflict)
1519 {
1520 conflicts_found = true;
1521
1522
1523 /* Mark end of conflict. */
1524
1525 fprintf (outputfile, "%lda\n", high0);
1526 leading_dot = false;
1527 if (type == DIFF_ALL)
1528 {
1529 if (show_2nd)
1530 {
1531 /* Append lines from FILE1. */
1532 fprintf (outputfile, "||||||| %s\n", file1);
1533 leading_dot = dotlines (outputfile, b, mapping[FILE1]);
1534 }
1535 /* Append lines from FILE2. */
1536 fprintf (outputfile, "=======\n");
1537 leading_dot |= dotlines (outputfile, b, mapping[FILE2]);
1538 }
1539 fprintf (outputfile, ">>>>>>> %s\n", file2);
1540 undotlines (outputfile, leading_dot, high0 + 2,
1541 (D_NUMLINES (b, mapping[FILE1])
1542 + D_NUMLINES (b, mapping[FILE2]) + 1));
1543
1544
1545 /* Mark start of conflict. */
1546
1547 fprintf (outputfile, "%lda\n<<<<<<< %s\n", low0 - 1,
1548 type == DIFF_ALL ? file0 : file1);
1549 leading_dot = false;
1550 if (type == DIFF_2ND)
1551 {
1552 /* Prepend lines from FILE1. */
1553 leading_dot = dotlines (outputfile, b, mapping[FILE1]);
1554 fprintf (outputfile, "=======\n");
1555 }
1556 undotlines (outputfile, leading_dot, low0 + 1,
1557 D_NUMLINES (b, mapping[FILE1]));
1558 }
1559 else if (D_NUMLINES (b, mapping[FILE2]) == 0)
1560 /* Write out a delete */
1561 {
1562 if (low0 == high0)
1563 fprintf (outputfile, "%ldd\n", low0);
1564 else
1565 fprintf (outputfile, "%ld,%ldd\n", low0, high0);
1566 }
1567 else
1568 /* Write out an add or change */
1569 {
1570 switch (high0 - low0)
1571 {
1572 case -1:
1573 fprintf (outputfile, "%lda\n", high0);
1574 break;
1575 case 0:
1576 fprintf (outputfile, "%ldc\n", high0);
1577 break;
1578 default:
1579 fprintf (outputfile, "%ld,%ldc\n", low0, high0);
1580 break;
1581 }
1582
1583 undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]),
1584 low0, D_NUMLINES (b, mapping[FILE2]));
1585 }
1586 }
1587 if (finalwrite) fprintf (outputfile, "w\nq\n");
1588 return conflicts_found;
1589 }
1590
1591 /* Read from INFILE and output to OUTPUTFILE a set of diff3_blocks
1592 DIFF as a merged file. This acts like 'ed file0
1593 <[output_diff3_edscript]', except that it works even for binary
1594 data or incomplete lines.
1595
1596 As before, MAPPING maps from arg list file number to diff file
1597 number, REV_MAPPING is its inverse, and FILE0, FILE1, and FILE2 are
1598 the names of the files.
1599
1600 Return 1 if conflicts were found. */
1601
1602 static bool
output_diff3_merge(FILE * infile,FILE * outputfile,struct diff3_block * diff,int const mapping[3],int const rev_mapping[3],char const * file0,char const * file1,char const * file2)1603 output_diff3_merge (FILE *infile, FILE *outputfile, struct diff3_block *diff,
1604 int const mapping[3], int const rev_mapping[3],
1605 char const *file0, char const *file1, char const *file2)
1606 {
1607 int c;
1608 lin i;
1609 bool conflicts_found = false;
1610 bool conflict;
1611 struct diff3_block *b;
1612 lin linesread = 0;
1613
1614 for (b = diff; b; b = b->next)
1615 {
1616 /* Must do mapping correctly. */
1617 enum diff_type type
1618 = ((b->correspond == DIFF_ALL)
1619 ? DIFF_ALL
1620 : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
1621 char const *format_2nd = "<<<<<<< %s\n";
1622
1623 /* If we aren't supposed to do this output block, skip it. */
1624 switch (type)
1625 {
1626 default: continue;
1627 case DIFF_2ND: if (!show_2nd) continue; conflict = true; break;
1628 case DIFF_3RD: if (overlap_only) continue; conflict = false; break;
1629 case DIFF_ALL: if (simple_only) continue; conflict = flagging;
1630 format_2nd = "||||||| %s\n";
1631 break;
1632 }
1633
1634 /* Copy I lines from file 0. */
1635 i = D_LOWLINE (b, FILE0) - linesread - 1;
1636 linesread += i;
1637 while (0 <= --i)
1638 do
1639 {
1640 c = getc (infile);
1641 if (c == EOF)
1642 {
1643 if (ferror (infile))
1644 perror_with_exit (_("read failed"));
1645 else if (feof (infile))
1646 fatal ("input file shrank");
1647 }
1648 putc (c, outputfile);
1649 }
1650 while (c != '\n');
1651
1652 if (conflict)
1653 {
1654 conflicts_found = true;
1655
1656 if (type == DIFF_ALL)
1657 {
1658 /* Put in lines from FILE0 with bracket. */
1659 fprintf (outputfile, "<<<<<<< %s\n", file0);
1660 for (i = 0;
1661 i < D_NUMLINES (b, mapping[FILE0]);
1662 i++)
1663 fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
1664 D_RELLEN (b, mapping[FILE0], i), outputfile);
1665 }
1666
1667 if (show_2nd)
1668 {
1669 /* Put in lines from FILE1 with bracket. */
1670 fprintf (outputfile, format_2nd, file1);
1671 for (i = 0;
1672 i < D_NUMLINES (b, mapping[FILE1]);
1673 i++)
1674 fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char),
1675 D_RELLEN (b, mapping[FILE1], i), outputfile);
1676 }
1677
1678 fprintf (outputfile, "=======\n");
1679 }
1680
1681 /* Put in lines from FILE2. */
1682 for (i = 0;
1683 i < D_NUMLINES (b, mapping[FILE2]);
1684 i++)
1685 fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
1686 D_RELLEN (b, mapping[FILE2], i), outputfile);
1687
1688 if (conflict)
1689 fprintf (outputfile, ">>>>>>> %s\n", file2);
1690
1691 /* Skip I lines in file 0. */
1692 i = D_NUMLINES (b, FILE0);
1693 linesread += i;
1694 while (0 <= --i)
1695 while ((c = getc (infile)) != '\n')
1696 if (c == EOF)
1697 {
1698 if (ferror (infile))
1699 perror_with_exit (_("read failed"));
1700 else if (feof (infile))
1701 {
1702 if (i || b->next)
1703 fatal ("input file shrank");
1704 return conflicts_found;
1705 }
1706 }
1707 }
1708 /* Copy rest of common file. */
1709 while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
1710 putc (c, outputfile);
1711 return conflicts_found;
1712 }
1713
1714 /* Reverse the order of the list of diff3 blocks. */
1715
1716 static struct diff3_block *
reverse_diff3_blocklist(struct diff3_block * diff)1717 reverse_diff3_blocklist (struct diff3_block *diff)
1718 {
1719 register struct diff3_block *tmp, *next, *prev;
1720
1721 for (tmp = diff, prev = 0; tmp; tmp = next)
1722 {
1723 next = tmp->next;
1724 tmp->next = prev;
1725 prev = tmp;
1726 }
1727
1728 return prev;
1729 }
1730
1731 static void
fatal(char const * msgid)1732 fatal (char const *msgid)
1733 {
1734 error (EXIT_TROUBLE, 0, "%s", _(msgid));
1735 abort ();
1736 }
1737
1738 static void
perror_with_exit(char const * string)1739 perror_with_exit (char const *string)
1740 {
1741 error (EXIT_TROUBLE, errno, "%s", string);
1742 abort ();
1743 }
1744