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