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