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