1 /* $NetBSD: diff3.c,v 1.2 2016/01/13 03:39:28 christos Exp $ */
2
3 /* diff3 - compare three files line by line
4
5 Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1998, 2001,
6 2002 Free Software Foundation, Inc.
7
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.
12
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.
17
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. */
22
23 #include "system.h"
24
25 static char const copyright_string[] =
26 "Copyright (C) 2002 Free Software Foundation, Inc.";
27
28 static char const authorship_msgid[] = N_("Written by Randy Smith.");
29
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>
40
41 extern char const version_string[];
42
43 /*
44 * Internal data structures and macros for the diff3 program; includes
45 * data structures for both diff3 diffs and normal diffs.
46 */
47
48 /* Different files within a three way diff. */
49 #define FILE0 0
50 #define FILE1 1
51 #define FILE2 2
52
53 /*
54 * A three way diff is built from two two-way diffs; the file which
55 * the two two-way diffs share is:
56 */
57 #define FILEC FILE2
58
59 /*
60 * Different files within a two way diff.
61 * FC is the common file, FO the other file.
62 */
63 #define FO 0
64 #define FC 1
65
66 /* The ranges are indexed by */
67 #define RANGE_START 0
68 #define RANGE_END 1
69
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 */
79 };
80
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;
87 };
88
89 /* Three way diff */
90
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;
97 };
98
99 /*
100 * Access the ranges on a diff block.
101 */
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)
108
109 /*
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.
113 */
114 #define D_RELNUM(diff, filenum, linenum) \
115 ((diff)->lines[filenum][linenum])
116 #define D_RELLEN(diff, filenum, linenum) \
117 ((diff)->lengths[filenum][linenum])
118
119 /*
120 * And get at them directly, when that should be necessary.
121 */
122 #define D_LINEARRAY(diff, filenum) \
123 ((diff)->lines[filenum])
124 #define D_LENARRAY(diff, filenum) \
125 ((diff)->lengths[filenum])
126
127 /*
128 * Next block.
129 */
130 #define D_NEXT(diff) ((diff)->next)
131
132 /*
133 * Access the type of a diff3 block.
134 */
135 #define D3_TYPE(diff) ((diff)->correspond)
136
137 /*
138 * Line mappings based on diffs. The first maps off the top of the
139 * diff, the second off of the bottom.
140 */
141 #define D_HIGH_MAPLINE(diff, fromfile, tofile, linenum) \
142 ((linenum) \
143 - D_HIGHLINE ((diff), (fromfile)) \
144 + D_HIGHLINE ((diff), (tofile)))
145
146 #define D_LOW_MAPLINE(diff, fromfile, tofile, linenum) \
147 ((linenum) \
148 - D_LOWLINE ((diff), (fromfile)) \
149 + D_LOWLINE ((diff), (tofile)))
150
151 /* Options variables for flags set on command line. */
152
153 /* If nonzero, treat all files as text files, never as binary. */
154 static bool text;
155
156 /* If nonzero, write out an ed script instead of the standard diff3 format. */
157 static bool edscript;
158
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;
163
164 /* Use a tab to align output lines (-T). */
165 static bool initial_tab;
166
167 /* If nonzero, do not output information for overlapping diffs. */
168 static bool simple_only;
169
170 /* If nonzero, do not output information for non-overlapping diffs. */
171 static bool overlap_only;
172
173 /* If nonzero, show information for DIFF_2ND diffs. */
174 static bool show_2nd;
175
176 /* If nonzero, include `:wq' at the end of the script
177 to write out the file being edited. */
178 static bool finalwrite;
179
180 /* If nonzero, output a merged file. */
181 static bool merge;
182
183 char *program_name;
184
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);
203
204 static char const *diff_program = DEFAULT_DIFF_PROGRAM;
205
206 /* Values for long options that do not have single-letter equivalents. */
207 enum
208 {
209 DIFF_PROGRAM_OPTION = CHAR_MAX + 1,
210 HELP_OPTION
211 };
212
213 static struct option const longopts[] =
214 {
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}
228 };
229
230 /*
231 * Main program. Calls diff twice on two pairs of input files,
232 * combines the two diffs, and outputs them.
233 */
234 int
main(int argc,char ** argv)235 main (int argc, char **argv)
236 {
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;
250
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);
258
259 while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != -1)
260 {
261 switch (c)
262 {
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)
313 {
314 tag_strings[tag_count++] = optarg;
315 break;
316 }
317 try_help ("too many file label options", 0);
318 default:
319 try_help (0, 0);
320 }
321 }
322
323 edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */
324 show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */
325 flagging |= ~incompat & merge;
326
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);
331
332 if (argc - optind != 3)
333 {
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]);
338 }
339
340 file = &argv[optind];
341
342 for (i = tag_count; i < 3; i++)
343 tag_strings[i] = file[i];
344
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.
351
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.
355
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. */
360
361 common = 2 - (edscript | merge);
362
363 if (strcmp (file[common], "-") == 0)
364 {
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");
371 }
372
373 mapping[0] = 0;
374 mapping[1] = 3 - common;
375 mapping[2] = common;
376
377 for (i = 0; i < 3; i++)
378 rev_mapping[mapping[i]] = i;
379
380 for (i = 0; i < 3; i++)
381 if (strcmp (file[i], "-") != 0)
382 {
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]);
387 }
388
389 #ifdef SIGCHLD
390 /* System V fork+wait does not work if SIGCHLD is ignored. */
391 signal (SIGCHLD, SIG_DFL);
392 #endif
393
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)
403 {
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");
411 }
412 else
413 {
414 output_diff3 (stdout, diff3, mapping, rev_mapping);
415 conflicts_found = 0;
416 }
417
418 check_stdout ();
419 exit (conflicts_found);
420 return conflicts_found;
421 }
422
423 static void
try_help(char const * reason_msgid,char const * operand)424 try_help (char const *reason_msgid, char const *operand)
425 {
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 ();
431 }
432
433 static void
check_stdout(void)434 check_stdout (void)
435 {
436 if (ferror (stdout))
437 fatal ("write failed");
438 else if (fclose (stdout) != 0)
439 perror_with_exit (_("standard output"));
440 }
441
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."),
449 "",
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."),
456 "",
457 N_("-v --version Output version info."),
458 N_("--help Output this help."),
459 0
460 };
461
462 static void
usage(void)463 usage (void)
464 {
465 char const * const *p;
466
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>."));
478 }
479
480 /*
481 * Routines that combine the two diffs together into one. The
482 * algorithm used follows:
483 *
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.
487 *
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.
496 *
497 * *If* the high water mark is above
498 * the low end of the range in that block,
499 *
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.
503 *
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.
507 *
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.
510 *
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).
514 *
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:
519 *
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.
524 *
525 * Then you do it again, until you run out of blocks.
526 *
527 */
528
529 /*
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.
536 */
537 static struct diff3_block *
make_3way_diff(struct diff_block * thread0,struct diff_block * thread1)538 make_3way_diff (struct diff_block *thread0, struct diff_block *thread1)
539 {
540 /*
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.
548 *
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.
556 *
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.
563 *
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.
568 */
569
570 struct diff_block *using[2];
571 struct diff_block *last_using[2];
572 struct diff_block *current[2];
573
574 lin high_water_mark;
575
576 int high_water_thread;
577 int base_water_thread;
578 int other_thread;
579
580 struct diff_block *high_water_diff;
581 struct diff_block *other_diff;
582
583 struct diff3_block *result;
584 struct diff3_block *tmpblock;
585 struct diff3_block **result_end;
586
587 struct diff3_block const *last_diff3;
588
589 static struct diff3_block const zero_diff3;
590
591 /* Initialization */
592 result = 0;
593 result_end = &result;
594 current[0] = thread0; current[1] = thread1;
595 last_diff3 = &zero_diff3;
596
597 /* Sniff up the threads until we reach the end */
598
599 while (current[0] || current[1])
600 {
601 using[0] = using[1] = last_using[0] = last_using[1] = 0;
602
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));
611
612 high_water_thread = base_water_thread;
613
614 high_water_diff = current[high_water_thread];
615
616 high_water_mark = D_HIGHLINE (high_water_diff, FC);
617
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;
624
625 /* And mark the other diff */
626 other_thread = high_water_thread ^ 0x1;
627 other_diff = current[other_thread];
628
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)
633 {
634
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;
642
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;
648
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. */
654
655 if (high_water_mark < D_HIGHLINE (other_diff, FC))
656 {
657 high_water_thread ^= 1;
658 high_water_diff = other_diff;
659 high_water_mark = D_HIGHLINE (other_diff, FC);
660 }
661
662 /* Set the other diff */
663 other_thread = high_water_thread ^ 0x1;
664 other_diff = current[other_thread];
665 }
666
667 /* The using lists contain a list of all of the blocks to be
668 included in this diff3_block. Create it. */
669
670 tmpblock = using_to_diff3_block (using, last_using,
671 base_water_thread, high_water_thread,
672 last_diff3);
673
674 if (!tmpblock)
675 fatal ("internal error: screwup in format of diff blocks");
676
677 /* Put it on the list. */
678 *result_end = tmpblock;
679 result_end = &tmpblock->next;
680
681 /* Set up corresponding lines correctly. */
682 last_diff3 = tmpblock;
683 }
684 return result;
685 }
686
687 /*
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.
692 *
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.
702 *
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.
706 */
707 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)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)
712 {
713 lin low[2], high[2];
714 struct diff3_block *result;
715 struct diff_block *ptr;
716 int d;
717 lin i;
718
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);
722
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. */
726
727 for (d = 0; d < 2; d++)
728 if (using[d])
729 {
730 low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
731 high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
732 }
733 else
734 {
735 low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
736 high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
737 }
738
739 /* Create a block with the appropriate sizes */
740 result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
741
742 /* Copy information for the common file.
743 Return with a zero if any of the compares failed. */
744
745 for (d = 0; d < 2; d++)
746 for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
747 {
748 lin result_offset = D_LOWLINE (ptr, FC) - lowc;
749
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;
756 }
757
758 /* Copy information for file d. First deal with anything that might be
759 before the first diff. */
760
761 for (d = 0; d < 2; d++)
762 {
763 struct diff_block *u = using[d];
764 lin lo = low[d], hi = high[d];
765
766 for (i = 0;
767 i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
768 i++)
769 {
770 D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
771 D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
772 }
773
774 for (ptr = u; ptr; ptr = D_NEXT (ptr))
775 {
776 lin result_offset = D_LOWLINE (ptr, FO) - lo;
777 lin linec;
778
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;
785
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++)
791 {
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++;
795 }
796 }
797 }
798
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
805 {
806 lin nl0 = D_NUMLINES (result, FILE0);
807 lin nl1 = D_NUMLINES (result, FILE1);
808
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;
818 }
819
820 return result;
821 }
822
823 /*
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.
829 */
830 static bool
copy_stringlist(char * const fromptrs[],size_t const fromlengths[],char * toptrs[],size_t tolengths[],lin copynum)831 copy_stringlist (char * const fromptrs[], size_t const fromlengths[],
832 char *toptrs[], size_t tolengths[],
833 lin copynum)
834 {
835 register char * const *f = fromptrs;
836 register char **t = toptrs;
837 register size_t const *fl = fromlengths;
838 register size_t *tl = tolengths;
839
840 while (copynum--)
841 {
842 if (*t)
843 { if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; }
844 else
845 { *t = *f ; *tl = *fl; }
846
847 t++; f++; tl++; fl++;
848 }
849 return 1;
850 }
851
852 /*
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.
856 */
857 static struct diff3_block *
create_diff3_block(lin low0,lin high0,lin low1,lin high1,lin low2,lin high2)858 create_diff3_block (lin low0, lin high0,
859 lin low1, lin high1,
860 lin low2, lin high2)
861 {
862 struct diff3_block *result = xmalloc (sizeof *result);
863 lin numlines;
864
865 D3_TYPE (result) = ERROR;
866 D_NEXT (result) = 0;
867
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;
875
876 /* Allocate and zero space */
877 numlines = D_NUMLINES (result, FILE0);
878 if (numlines)
879 {
880 D_LINEARRAY (result, FILE0) = xcalloc (numlines, sizeof (char *));
881 D_LENARRAY (result, FILE0) = xcalloc (numlines, sizeof (size_t));
882 }
883 else
884 {
885 D_LINEARRAY (result, FILE0) = 0;
886 D_LENARRAY (result, FILE0) = 0;
887 }
888
889 numlines = D_NUMLINES (result, FILE1);
890 if (numlines)
891 {
892 D_LINEARRAY (result, FILE1) = xcalloc (numlines, sizeof (char *));
893 D_LENARRAY (result, FILE1) = xcalloc (numlines, sizeof (size_t));
894 }
895 else
896 {
897 D_LINEARRAY (result, FILE1) = 0;
898 D_LENARRAY (result, FILE1) = 0;
899 }
900
901 numlines = D_NUMLINES (result, FILE2);
902 if (numlines)
903 {
904 D_LINEARRAY (result, FILE2) = xcalloc (numlines, sizeof (char *));
905 D_LENARRAY (result, FILE2) = xcalloc (numlines, sizeof (size_t));
906 }
907 else
908 {
909 D_LINEARRAY (result, FILE2) = 0;
910 D_LENARRAY (result, FILE2) = 0;
911 }
912
913 /* Return */
914 return result;
915 }
916
917 /*
918 * Compare two lists of lines of text.
919 * Return 1 if they are equivalent, 0 if not.
920 */
921 static bool
compare_line_list(char * const list1[],size_t const lengths1[],char * const list2[],size_t const lengths2[],lin nl)922 compare_line_list (char * const list1[], size_t const lengths1[],
923 char * const list2[], size_t const lengths2[],
924 lin nl)
925 {
926 char
927 * const *l1 = list1,
928 * const *l2 = list2;
929 size_t const
930 *lgths1 = lengths1,
931 *lgths2 = lengths2;
932
933 while (nl--)
934 if (!*l1 || !*l2 || *lgths1 != *lgths2++
935 || memcmp (*l1++, *l2++, *lgths1++))
936 return 0;
937 return 1;
938 }
939
940 /*
941 * Routines to input and parse two way diffs.
942 */
943
944 static struct diff_block *
process_diff(char const * filea,char const * fileb,struct diff_block ** last_block)945 process_diff (char const *filea,
946 char const *fileb,
947 struct diff_block **last_block)
948 {
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]));
958
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'. */
963
964 while (scan_diff < diff_limit)
965 {
966 bptr = xmalloc (sizeof *bptr);
967 bptr->lines[0] = bptr->lines[1] = 0;
968 bptr->lengths[0] = bptr->lengths[1] = 0;
969
970 dt = process_diff_control (&scan_diff, bptr);
971 if (dt == ERROR || *scan_diff != '\n')
972 {
973 fprintf (stderr, _("%s: diff failed: "), program_name);
974 do
975 {
976 putc (*scan_diff, stderr);
977 }
978 while (*scan_diff++ != '\n');
979 exit (EXIT_TROUBLE);
980 }
981 scan_diff++;
982
983 /* Force appropriate ranges to be null, if necessary */
984 switch (dt)
985 {
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;
997 }
998
999 /* Allocate space for the pointers for the lines from filea, and
1000 parcel them out among these pointers */
1001 if (dt != ADD)
1002 {
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 '<');
1014 }
1015
1016 /* Get past the separator for changes */
1017 if (dt == CHANGE)
1018 {
1019 if (strncmp (scan_diff, "---\n", 4))
1020 fatal ("invalid diff format; invalid change separator");
1021 scan_diff += 4;
1022 }
1023
1024 /* Allocate space for the pointers for the lines from fileb, and
1025 parcel them out among these pointers */
1026 if (dt != DELETE)
1027 {
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 '>');
1039 }
1040
1041 /* Place this block on the blocklist. */
1042 *block_list_end = bptr;
1043 block_list_end = &bptr->next;
1044 }
1045
1046 *block_list_end = 0;
1047 *last_block = bptr;
1048 return block_list;
1049 }
1050
1051 /*
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.
1059 *
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.
1065 */
1066
1067 static enum diff_type
process_diff_control(char ** string,struct diff_block * db)1068 process_diff_control (char **string, struct diff_block *db)
1069 {
1070 char *s = *string;
1071 lin holdnum;
1072 enum diff_type type;
1073
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!
1077
1078 Also note that SKIPWHITE only recognizes tabs and spaces, and
1079 that READNUM can only read positive, integral numbers */
1080
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; }
1086
1087 /* Read first set of digits */
1088 SKIPWHITE (s);
1089 READNUM (s, db->ranges[0][RANGE_START]);
1090
1091 /* Was that the only digit? */
1092 SKIPWHITE (s);
1093 if (*s == ',')
1094 {
1095 /* Get the next digit */
1096 s++;
1097 READNUM (s, db->ranges[0][RANGE_END]);
1098 }
1099 else
1100 db->ranges[0][RANGE_END] = db->ranges[0][RANGE_START];
1101
1102 /* Get the letter */
1103 SKIPWHITE (s);
1104 switch (*s)
1105 {
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 */
1117 }
1118 s++; /* Past letter */
1119
1120 /* Read second set of digits */
1121 SKIPWHITE (s);
1122 READNUM (s, db->ranges[1][RANGE_START]);
1123
1124 /* Was that the only digit? */
1125 SKIPWHITE (s);
1126 if (*s == ',')
1127 {
1128 /* Get the next digit */
1129 s++;
1130 READNUM (s, db->ranges[1][RANGE_END]);
1131 SKIPWHITE (s); /* To move to end */
1132 }
1133 else
1134 db->ranges[1][RANGE_END] = db->ranges[1][RANGE_START];
1135
1136 *string = s;
1137 return type;
1138 }
1139
1140 static char *
read_diff(char const * filea,char const * fileb,char ** output_placement)1141 read_diff (char const *filea,
1142 char const *fileb,
1143 char **output_placement)
1144 {
1145 char *diff_result;
1146 size_t current_chunk_size, total;
1147 int fd, wstatus;
1148 int werrno = 0;
1149 struct stat pipestat;
1150
1151 #if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
1152
1153 char const *argv[8];
1154 char const **ap;
1155 int fds[2];
1156 pid_t pid;
1157
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;
1167
1168 if (pipe (fds) != 0)
1169 perror_with_exit ("pipe");
1170
1171 pid = vfork ();
1172 if (pid == 0)
1173 {
1174 /* Child */
1175 close (fds[0]);
1176 if (fds[1] != STDOUT_FILENO)
1177 {
1178 dup2 (fds[1], STDOUT_FILENO);
1179 close (fds[1]);
1180 }
1181
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);
1185
1186 _exit (errno == ENOEXEC ? 126 : 127);
1187 }
1188
1189 if (pid == -1)
1190 perror_with_exit ("fork");
1191
1192 close (fds[1]); /* Prevent erroneous lack of EOF */
1193 fd = fds[0];
1194
1195 #else
1196
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);
1217
1218 #endif
1219
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;
1225
1226 for (;;)
1227 {
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)
1232 {
1233 if (bytes == SIZE_MAX)
1234 perror_with_exit (_("read failed"));
1235 break;
1236 }
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);
1241 }
1242
1243 if (total != 0 && diff_result[total-1] != '\n')
1244 fatal ("invalid diff format; incomplete last line");
1245
1246 *output_placement = diff_result;
1247
1248 #if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
1249
1250 wstatus = pclose (fpipe);
1251 if (wstatus == -1)
1252 werrno = errno;
1253
1254 #else
1255
1256 if (close (fd) != 0)
1257 perror_with_exit ("close");
1258 if (waitpid (pid, &wstatus, 0) < 0)
1259 perror_with_exit ("waitpid");
1260
1261 #endif
1262
1263 if (! werrno && WIFEXITED (wstatus))
1264 switch (WEXITSTATUS (wstatus))
1265 {
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);
1272 }
1273 if (werrno || ! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
1274 error (EXIT_TROUBLE, werrno, _("subsidiary program `%s' failed"),
1275 diff_program);
1276
1277 return diff_result + total;
1278 }
1279
1280
1281 /*
1282 * Scan a regular diff line (consisting of > or <, followed by a
1283 * space, followed by text (including nulls) up to a newline.
1284 *
1285 * This next routine began life as a macro and many parameters in it
1286 * are used as call-by-reference values.
1287 */
1288 static char *
scan_diff_line(char * scan_ptr,char ** set_start,size_t * set_length,char * limit,char leadingchar)1289 scan_diff_line (char *scan_ptr, char **set_start, size_t *set_length,
1290 char *limit, char leadingchar)
1291 {
1292 char *line_ptr;
1293
1294 if (!(scan_ptr[0] == leadingchar
1295 && scan_ptr[1] == ' '))
1296 fatal ("invalid diff format; incorrect leading line chars");
1297
1298 *set_start = line_ptr = scan_ptr + 2;
1299 while (*line_ptr++ != '\n')
1300 continue;
1301
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 == '\\')
1309 {
1310 if (edscript)
1311 fprintf (stderr, "%s:", program_name);
1312 else
1313 --*set_length;
1314 line_ptr++;
1315 do
1316 {
1317 if (edscript)
1318 putc (*line_ptr, stderr);
1319 }
1320 while (*line_ptr++ != '\n');
1321 }
1322
1323 return line_ptr;
1324 }
1325
1326 /*
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.
1336 */
1337 static void
output_diff3(FILE * outputfile,struct diff3_block * diff,int const mapping[3],int const rev_mapping[3])1338 output_diff3 (FILE *outputfile, struct diff3_block *diff,
1339 int const mapping[3], int const rev_mapping[3])
1340 {
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" : " ";
1350
1351 for (ptr = diff; ptr; ptr = D_NEXT (ptr))
1352 {
1353 char x[2];
1354
1355 switch (ptr->correspond)
1356 {
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];
1366
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");
1373 }
1374 fprintf (outputfile, "====%s\n", x);
1375
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))
1379 {
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;
1385
1386 fprintf (outputfile, "%d:", i + 1);
1387 switch (lowt - hight)
1388 {
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;
1398 }
1399
1400 if (i == dontprint) continue;
1401
1402 if (lowt <= hight)
1403 {
1404 line = 0;
1405 do
1406 {
1407 fprintf (outputfile, "%s", line_prefix);
1408 cp = D_RELNUM (ptr, realfile, line);
1409 length = D_RELLEN (ptr, realfile, line);
1410 fwrite (cp, sizeof (char), length, outputfile);
1411 }
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"));
1416 }
1417 }
1418 }
1419 }
1420
1421
1422 /*
1423 * Output to OUTPUTFILE the lines of B taken from FILENUM.
1424 * Double any 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 = 0;
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 = 1;
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 /*
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.)
1454 */
1455 static void
undotlines(FILE * outputfile,bool leading_dot,long start,lin num)1456 undotlines (FILE *outputfile, bool leading_dot, long start, lin num)
1457 {
1458 fprintf (outputfile, ".\n");
1459 if (leading_dot)
1460 {
1461 if (num == 1)
1462 fprintf (outputfile, "%lds/^\\.//\n", start);
1463 else
1464 fprintf (outputfile, "%ld,%lds/^\\.//\n", start, start + num - 1);
1465 }
1466 }
1467
1468 /*
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).
1476 *
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.
1482 *
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.
1486 *
1487 * Returns 1 if conflicts were found.
1488 */
1489
1490 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)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)
1494 {
1495 bool leading_dot;
1496 bool conflicts_found = 0, conflict;
1497 struct diff3_block *b;
1498
1499 for (b = reverse_diff3_blocklist (diff); b; b = b->next)
1500 {
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]);
1506
1507 long low0, high0;
1508
1509 /* If we aren't supposed to do this output block, skip it. */
1510 switch (type)
1511 {
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;
1516 }
1517
1518 low0 = D_LOWLINE (b, mapping[FILE0]);
1519 high0 = D_HIGHLINE (b, mapping[FILE0]);
1520
1521 if (conflict)
1522 {
1523 conflicts_found = 1;
1524
1525
1526 /* Mark end of conflict. */
1527
1528 fprintf (outputfile, "%lda\n", high0);
1529 leading_dot = 0;
1530 if (type == DIFF_ALL)
1531 {
1532 if (show_2nd)
1533 {
1534 /* Append lines from FILE1. */
1535 fprintf (outputfile, "||||||| %s\n", file1);
1536 leading_dot = dotlines (outputfile, b, mapping[FILE1]);
1537 }
1538 /* Append lines from FILE2. */
1539 fprintf (outputfile, "=======\n");
1540 leading_dot |= dotlines (outputfile, b, mapping[FILE2]);
1541 }
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));
1546
1547
1548 /* Mark start of conflict. */
1549
1550 fprintf (outputfile, "%lda\n<<<<<<< %s\n", low0 - 1,
1551 type == DIFF_ALL ? file0 : file1);
1552 leading_dot = 0;
1553 if (type == DIFF_2ND)
1554 {
1555 /* Prepend lines from FILE1. */
1556 leading_dot = dotlines (outputfile, b, mapping[FILE1]);
1557 fprintf (outputfile, "=======\n");
1558 }
1559 undotlines (outputfile, leading_dot, low0 + 1,
1560 D_NUMLINES (b, mapping[FILE1]));
1561 }
1562 else if (D_NUMLINES (b, mapping[FILE2]) == 0)
1563 /* Write out a delete */
1564 {
1565 if (low0 == high0)
1566 fprintf (outputfile, "%ldd\n", low0);
1567 else
1568 fprintf (outputfile, "%ld,%ldd\n", low0, high0);
1569 }
1570 else
1571 /* Write out an add or change */
1572 {
1573 switch (high0 - low0)
1574 {
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;
1584 }
1585
1586 undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]),
1587 low0, D_NUMLINES (b, mapping[FILE2]));
1588 }
1589 }
1590 if (finalwrite) fprintf (outputfile, "w\nq\n");
1591 return conflicts_found;
1592 }
1593
1594 /*
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.
1598 *
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.
1602 *
1603 * Returns 1 if conflicts were found.
1604 */
1605
1606 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)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)
1610 {
1611 int c;
1612 lin i;
1613 bool conflicts_found = 0, conflict;
1614 struct diff3_block *b;
1615 lin linesread = 0;
1616
1617 for (b = diff; b; b = b->next)
1618 {
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";
1625
1626 /* If we aren't supposed to do this output block, skip it. */
1627 switch (type)
1628 {
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;
1635 }
1636
1637 /* Copy I lines from file 0. */
1638 i = D_LOWLINE (b, FILE0) - linesread - 1;
1639 linesread += i;
1640 while (0 <= --i)
1641 do
1642 {
1643 c = getc (infile);
1644 if (c == EOF)
1645 {
1646 if (ferror (infile))
1647 perror_with_exit (_("read failed"));
1648 else if (feof (infile))
1649 fatal ("input file shrank");
1650 }
1651 putc (c, outputfile);
1652 }
1653 while (c != '\n');
1654
1655 if (conflict)
1656 {
1657 conflicts_found = 1;
1658
1659 if (type == DIFF_ALL)
1660 {
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);
1668 }
1669
1670 if (show_2nd)
1671 {
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);
1679 }
1680
1681 fprintf (outputfile, "=======\n");
1682 }
1683
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);
1690
1691 if (conflict)
1692 fprintf (outputfile, ">>>>>>> %s\n", file2);
1693
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)
1700 {
1701 if (ferror (infile))
1702 perror_with_exit (_("read failed"));
1703 else if (feof (infile))
1704 {
1705 if (i || b->next)
1706 fatal ("input file shrank");
1707 return conflicts_found;
1708 }
1709 }
1710 }
1711 /* Copy rest of common file. */
1712 while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
1713 putc (c, outputfile);
1714 return conflicts_found;
1715 }
1716
1717 /*
1718 * Reverse the order of the list of diff3 blocks.
1719 */
1720 static struct diff3_block *
reverse_diff3_blocklist(struct diff3_block * diff)1721 reverse_diff3_blocklist (struct diff3_block *diff)
1722 {
1723 register struct diff3_block *tmp, *next, *prev;
1724
1725 for (tmp = diff, prev = 0; tmp; tmp = next)
1726 {
1727 next = tmp->next;
1728 tmp->next = prev;
1729 prev = tmp;
1730 }
1731
1732 return prev;
1733 }
1734
1735 static void
fatal(char const * msgid)1736 fatal (char const *msgid)
1737 {
1738 error (EXIT_TROUBLE, 0, "%s", _(msgid));
1739 abort ();
1740 }
1741
1742 static void
perror_with_exit(char const * string)1743 perror_with_exit (char const *string)
1744 {
1745 error (EXIT_TROUBLE, errno, "%s", string);
1746 abort ();
1747 }
1748