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