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