| File: | src/gnu/usr.bin/cvs/diff/diff3.c |
| Warning: | line 968, column 9 Dereference of null pointer (loaded from variable 'f') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* Three way file comparison program (diff3) for Project GNU. | ||||
| 2 | Copyright (C) 1988, 1989, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc. | ||||
| 3 | |||||
| 4 | This program is free software; you can redistribute it and/or modify | ||||
| 5 | it under the terms of the GNU General Public License as published by | ||||
| 6 | the Free Software Foundation; either version 2, or (at your option) | ||||
| 7 | any later version. | ||||
| 8 | |||||
| 9 | This program is distributed in the hope that it will be useful, | ||||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| 12 | GNU General Public License for more details. | ||||
| 13 | |||||
| 14 | */ | ||||
| 15 | |||||
| 16 | /* Written by Randy Smith */ | ||||
| 17 | /* Librarification by Tim Pierce */ | ||||
| 18 | |||||
| 19 | #include "system.h" | ||||
| 20 | #include <stdio.h> | ||||
| 21 | #include <setjmp.h> | ||||
| 22 | #include "getopt.h" | ||||
| 23 | #include "diffrun.h" | ||||
| 24 | |||||
| 25 | /* diff3.c has a real initialize_main function. */ | ||||
| 26 | #ifdef initialize_main | ||||
| 27 | #undef initialize_main | ||||
| 28 | #endif | ||||
| 29 | |||||
| 30 | extern char const diff_version_string[]; | ||||
| 31 | |||||
| 32 | extern FILE *outfile; | ||||
| 33 | |||||
| 34 | extern const struct diff_callbacks *callbacks; | ||||
| 35 | |||||
| 36 | void write_output PARAMS((char const *, size_t))(char const *, size_t); | ||||
| 37 | void printf_output PARAMS((char const *, ...))(char const *, ...) | ||||
| 38 | #if __GNUC__4 > 2 || (__GNUC__4 == 2 && __GNUC_MINOR__2 > 6) | ||||
| 39 | __attribute__ ((__format__ (__printf__, 1, 2))) | ||||
| 40 | #endif | ||||
| 41 | ; | ||||
| 42 | void flush_output PARAMS((void))(void); | ||||
| 43 | |||||
| 44 | char * cvs_temp_name PARAMS((void))(void); | ||||
| 45 | |||||
| 46 | /* | ||||
| 47 | * Internal data structures and macros for the diff3 program; includes | ||||
| 48 | * data structures for both diff3 diffs and normal diffs. | ||||
| 49 | */ | ||||
| 50 | |||||
| 51 | /* Different files within a three way diff. */ | ||||
| 52 | #define FILE00 0 | ||||
| 53 | #define FILE11 1 | ||||
| 54 | #define FILE22 2 | ||||
| 55 | |||||
| 56 | /* | ||||
| 57 | * A three way diff is built from two two-way diffs; the file which | ||||
| 58 | * the two two-way diffs share is: | ||||
| 59 | */ | ||||
| 60 | #define FILEC2 FILE22 | ||||
| 61 | |||||
| 62 | /* | ||||
| 63 | * Different files within a two way diff. | ||||
| 64 | * FC is the common file, FO the other file. | ||||
| 65 | */ | ||||
| 66 | #define FO0 0 | ||||
| 67 | #define FC1 1 | ||||
| 68 | |||||
| 69 | /* The ranges are indexed by */ | ||||
| 70 | #define START0 0 | ||||
| 71 | #define END1 1 | ||||
| 72 | |||||
| 73 | enum diff_type { | ||||
| 74 | ERROR, /* Should not be used */ | ||||
| 75 | ADD, /* Two way diff add */ | ||||
| 76 | CHANGE, /* Two way diff change */ | ||||
| 77 | DELETE, /* Two way diff delete */ | ||||
| 78 | DIFF_ALL, /* All three are different */ | ||||
| 79 | DIFF_1ST, /* Only the first is different */ | ||||
| 80 | DIFF_2ND, /* Only the second */ | ||||
| 81 | DIFF_3RD /* Only the third */ | ||||
| 82 | }; | ||||
| 83 | |||||
| 84 | /* Two way diff */ | ||||
| 85 | struct diff_block { | ||||
| 86 | int ranges[2][2]; /* Ranges are inclusive */ | ||||
| 87 | char **lines[2]; /* The actual lines (may contain nulls) */ | ||||
| 88 | size_t *lengths[2]; /* Line lengths (including newlines, if any) */ | ||||
| 89 | struct diff_block *next; | ||||
| 90 | }; | ||||
| 91 | |||||
| 92 | /* Three way diff */ | ||||
| 93 | |||||
| 94 | struct diff3_block { | ||||
| 95 | enum diff_type correspond; /* Type of diff */ | ||||
| 96 | int ranges[3][2]; /* Ranges are inclusive */ | ||||
| 97 | char **lines[3]; /* The actual lines (may contain nulls) */ | ||||
| 98 | size_t *lengths[3]; /* Line lengths (including newlines, if any) */ | ||||
| 99 | struct diff3_block *next; | ||||
| 100 | }; | ||||
| 101 | |||||
| 102 | /* | ||||
| 103 | * Access the ranges on a diff block. | ||||
| 104 | */ | ||||
| 105 | #define D_LOWLINE(diff, filenum)((diff)->ranges[filenum][0]) \ | ||||
| 106 | ((diff)->ranges[filenum][START0]) | ||||
| 107 | #define D_HIGHLINE(diff, filenum)((diff)->ranges[filenum][1]) \ | ||||
| 108 | ((diff)->ranges[filenum][END1]) | ||||
| 109 | #define D_NUMLINES(diff, filenum)(((diff)->ranges[filenum][1]) - ((diff)->ranges[filenum ][0]) + 1) \ | ||||
| 110 | (D_HIGHLINE (diff, filenum)((diff)->ranges[filenum][1]) - D_LOWLINE (diff, filenum)((diff)->ranges[filenum][0]) + 1) | ||||
| 111 | |||||
| 112 | /* | ||||
| 113 | * Access the line numbers in a file in a diff by relative line | ||||
| 114 | * numbers (i.e. line number within the diff itself). Note that these | ||||
| 115 | * are lvalues and can be used for assignment. | ||||
| 116 | */ | ||||
| 117 | #define D_RELNUM(diff, filenum, linenum)((diff)->lines[filenum][linenum]) \ | ||||
| 118 | ((diff)->lines[filenum][linenum]) | ||||
| 119 | #define D_RELLEN(diff, filenum, linenum)((diff)->lengths[filenum][linenum]) \ | ||||
| 120 | ((diff)->lengths[filenum][linenum]) | ||||
| 121 | |||||
| 122 | /* | ||||
| 123 | * And get at them directly, when that should be necessary. | ||||
| 124 | */ | ||||
| 125 | #define D_LINEARRAY(diff, filenum)((diff)->lines[filenum]) \ | ||||
| 126 | ((diff)->lines[filenum]) | ||||
| 127 | #define D_LENARRAY(diff, filenum)((diff)->lengths[filenum]) \ | ||||
| 128 | ((diff)->lengths[filenum]) | ||||
| 129 | |||||
| 130 | /* | ||||
| 131 | * Next block. | ||||
| 132 | */ | ||||
| 133 | #define D_NEXT(diff)((diff)->next) ((diff)->next) | ||||
| 134 | |||||
| 135 | /* | ||||
| 136 | * Access the type of a diff3 block. | ||||
| 137 | */ | ||||
| 138 | #define D3_TYPE(diff)((diff)->correspond) ((diff)->correspond) | ||||
| 139 | |||||
| 140 | /* | ||||
| 141 | * Line mappings based on diffs. The first maps off the top of the | ||||
| 142 | * diff, the second off of the bottom. | ||||
| 143 | */ | ||||
| 144 | #define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno)((lineno) - (((diff))->ranges[(fromfile)][1]) + (((diff))-> ranges[(tofile)][1])) \ | ||||
| 145 | ((lineno) \ | ||||
| 146 | - D_HIGHLINE ((diff), (fromfile))(((diff))->ranges[(fromfile)][1]) \ | ||||
| 147 | + D_HIGHLINE ((diff), (tofile))(((diff))->ranges[(tofile)][1])) | ||||
| 148 | |||||
| 149 | #define D_LOW_MAPLINE(diff, fromfile, tofile, lineno)((lineno) - (((diff))->ranges[(fromfile)][0]) + (((diff))-> ranges[(tofile)][0])) \ | ||||
| 150 | ((lineno) \ | ||||
| 151 | - D_LOWLINE ((diff), (fromfile))(((diff))->ranges[(fromfile)][0]) \ | ||||
| 152 | + D_LOWLINE ((diff), (tofile))(((diff))->ranges[(tofile)][0])) | ||||
| 153 | |||||
| 154 | /* | ||||
| 155 | * General memory allocation function. | ||||
| 156 | */ | ||||
| 157 | #define ALLOCATE(number, type)(type *) xmalloc ((number) * sizeof (type)) \ | ||||
| 158 | (type *) xmalloc ((number) * sizeof (type)) | ||||
| 159 | |||||
| 160 | /* Options variables for flags set on command line. */ | ||||
| 161 | |||||
| 162 | /* If nonzero, treat all files as text files, never as binary. */ | ||||
| 163 | static int always_text; | ||||
| 164 | |||||
| 165 | /* If nonzero, write out an ed script instead of the standard diff3 format. */ | ||||
| 166 | static int edscript; | ||||
| 167 | |||||
| 168 | /* If nonzero, in the case of overlapping diffs (type DIFF_ALL), | ||||
| 169 | preserve the lines which would normally be deleted from | ||||
| 170 | file 1 with a special flagging mechanism. */ | ||||
| 171 | static int flagging; | ||||
| 172 | |||||
| 173 | /* Number of lines to keep in identical prefix and suffix. */ | ||||
| 174 | static int const horizon_lines = 10; | ||||
| 175 | |||||
| 176 | /* Use a tab to align output lines (-T). */ | ||||
| 177 | static int tab_align_flag; | ||||
| 178 | |||||
| 179 | /* If nonzero, do not output information for overlapping diffs. */ | ||||
| 180 | static int simple_only; | ||||
| 181 | |||||
| 182 | /* If nonzero, do not output information for non-overlapping diffs. */ | ||||
| 183 | static int overlap_only; | ||||
| 184 | |||||
| 185 | /* If nonzero, show information for DIFF_2ND diffs. */ | ||||
| 186 | static int show_2nd; | ||||
| 187 | |||||
| 188 | /* If nonzero, include `:wq' at the end of the script | ||||
| 189 | to write out the file being edited. */ | ||||
| 190 | static int finalwrite; | ||||
| 191 | |||||
| 192 | /* If nonzero, output a merged file. */ | ||||
| 193 | static int merge; | ||||
| 194 | |||||
| 195 | extern char *diff_program_name; | ||||
| 196 | |||||
| 197 | static char *read_diff PARAMS((char const *, char const *, char **))(char const *, char const *, char **); | ||||
| 198 | static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int))(char *, char **, size_t *, char *, int); | ||||
| 199 | static enum diff_type process_diff_control PARAMS((char **, struct diff_block *))(char **, struct diff_block *); | ||||
| 200 | static int compare_line_list PARAMS((char * const[], size_t const[], char * const[], size_t const[], int))(char * const[], size_t const[], char * const[], size_t const [], int); | ||||
| 201 | static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int))(char * const[], size_t const[], char *[], size_t[], int); | ||||
| 202 | static int dotlines PARAMS((struct diff3_block *, int))(struct diff3_block *, int); | ||||
| 203 | static int output_diff3_edscript PARAMS((struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *))(struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *); | ||||
| 204 | static int output_diff3_merge PARAMS((FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *))(FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *); | ||||
| 205 | static size_t myread PARAMS((int, char *, size_t))(int, char *, size_t); | ||||
| 206 | static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int))(int, int, int, int, int, int); | ||||
| 207 | static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *))(struct diff_block *, struct diff_block *); | ||||
| 208 | static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *))(struct diff3_block *); | ||||
| 209 | static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *))(struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *); | ||||
| 210 | static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **, char **))(char const *, char const *, struct diff_block **, char **); | ||||
| 211 | static void check_output PARAMS((FILE *))(FILE *); | ||||
| 212 | static void diff3_fatal PARAMS((char const *))(char const *); | ||||
| 213 | static void output_diff3 PARAMS((struct diff3_block *, int const[3], int const[3]))(struct diff3_block *, int const[3], int const[3]); | ||||
| 214 | static void diff3_perror_with_exit PARAMS((char const *))(char const *); | ||||
| 215 | static int try_help PARAMS((char const *))(char const *); | ||||
| 216 | static void undotlines PARAMS((int, int, int))(int, int, int); | ||||
| 217 | static void usage PARAMS((void))(void); | ||||
| 218 | static void initialize_main PARAMS((int *, char ***))(int *, char ***); | ||||
| 219 | static void free_diff_blocks PARAMS((struct diff_block *))(struct diff_block *); | ||||
| 220 | static void free_diff3_blocks PARAMS((struct diff3_block *))(struct diff3_block *); | ||||
| 221 | |||||
| 222 | /* Functions provided in libdiff.a or other external sources. */ | ||||
| 223 | VOIDvoid *xmalloc PARAMS((size_t))(size_t); | ||||
| 224 | VOIDvoid *xrealloc PARAMS((VOID *, size_t))(void *, size_t); | ||||
| 225 | void perror_with_name PARAMS((char const *))(char const *); | ||||
| 226 | void diff_error PARAMS((char const *, char const *, char const *))(char const *, char const *, char const *); | ||||
| 227 | |||||
| 228 | /* Permit non-local exits from diff3. */ | ||||
| 229 | static jmp_buf diff3_abort_buf; | ||||
| 230 | #define DIFF3_ABORT(retval)longjmp(diff3_abort_buf, retval) longjmp(diff3_abort_buf, retval) | ||||
| 231 | |||||
| 232 | static struct option const longopts[] = | ||||
| 233 | { | ||||
| 234 | {"text", 0, 0, 'a'}, | ||||
| 235 | {"show-all", 0, 0, 'A'}, | ||||
| 236 | {"ed", 0, 0, 'e'}, | ||||
| 237 | {"show-overlap", 0, 0, 'E'}, | ||||
| 238 | {"label", 1, 0, 'L'}, | ||||
| 239 | {"merge", 0, 0, 'm'}, | ||||
| 240 | {"initial-tab", 0, 0, 'T'}, | ||||
| 241 | {"overlap-only", 0, 0, 'x'}, | ||||
| 242 | {"easy-only", 0, 0, '3'}, | ||||
| 243 | {"version", 0, 0, 'v'}, | ||||
| 244 | {"help", 0, 0, 129}, | ||||
| 245 | {0, 0, 0, 0} | ||||
| 246 | }; | ||||
| 247 | |||||
| 248 | /* | ||||
| 249 | * Main program. Calls diff twice on two pairs of input files, | ||||
| 250 | * combines the two diffs, and outputs them. | ||||
| 251 | */ | ||||
| 252 | int | ||||
| 253 | diff3_run (argc, argv, out, callbacks_arg) | ||||
| 254 | int argc; | ||||
| 255 | char **argv; | ||||
| 256 | char *out; | ||||
| 257 | const struct diff_callbacks *callbacks_arg; | ||||
| 258 | { | ||||
| 259 | int c, i; | ||||
| 260 | int mapping[3]; | ||||
| 261 | int rev_mapping[3]; | ||||
| 262 | int incompat = 0; | ||||
| 263 | int conflicts_found; | ||||
| 264 | int status; | ||||
| 265 | struct diff_block *thread0, *thread1, *last_block; | ||||
| 266 | char *content0, *content1; | ||||
| 267 | struct diff3_block *diff3; | ||||
| 268 | int tag_count = 0; | ||||
| 269 | char *tag_strings[3]; | ||||
| 270 | char *commonname; | ||||
| 271 | char **file; | ||||
| 272 | struct stat statb; | ||||
| 273 | int optind_old; | ||||
| 274 | int opened_file = 0; | ||||
| 275 | |||||
| 276 | callbacks = callbacks_arg; | ||||
| 277 | |||||
| 278 | initialize_main (&argc, &argv); | ||||
| 279 | |||||
| 280 | optind_old = optind; | ||||
| 281 | optind = 0; | ||||
| 282 | while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF(-1)) | ||||
| |||||
| 283 | { | ||||
| 284 | switch (c) | ||||
| 285 | { | ||||
| 286 | case 'a': | ||||
| 287 | always_text = 1; | ||||
| 288 | break; | ||||
| 289 | case 'A': | ||||
| 290 | show_2nd = 1; | ||||
| 291 | flagging = 1; | ||||
| 292 | incompat++; | ||||
| 293 | break; | ||||
| 294 | case 'x': | ||||
| 295 | overlap_only = 1; | ||||
| 296 | incompat++; | ||||
| 297 | break; | ||||
| 298 | case '3': | ||||
| 299 | simple_only = 1; | ||||
| 300 | incompat++; | ||||
| 301 | break; | ||||
| 302 | case 'i': | ||||
| 303 | finalwrite = 1; | ||||
| 304 | break; | ||||
| 305 | case 'm': | ||||
| 306 | merge = 1; | ||||
| 307 | break; | ||||
| 308 | case 'X': | ||||
| 309 | overlap_only = 1; | ||||
| 310 | /* Falls through */ | ||||
| 311 | case 'E': | ||||
| 312 | flagging = 1; | ||||
| 313 | /* Falls through */ | ||||
| 314 | case 'e': | ||||
| 315 | incompat++; | ||||
| 316 | break; | ||||
| 317 | case 'T': | ||||
| 318 | tab_align_flag = 1; | ||||
| 319 | break; | ||||
| 320 | case 'v': | ||||
| 321 | if (callbacks && callbacks->write_stdout) | ||||
| 322 | { | ||||
| 323 | (*callbacks->write_stdout) ("diff3 - GNU diffutils version "); | ||||
| 324 | (*callbacks->write_stdout) (diff_version_string); | ||||
| 325 | (*callbacks->write_stdout) ("\n"); | ||||
| 326 | } | ||||
| 327 | else | ||||
| 328 | printf ("diff3 - GNU diffutils version %s\n", diff_version_string); | ||||
| 329 | return 0; | ||||
| 330 | case 129: | ||||
| 331 | usage (); | ||||
| 332 | if (! callbacks || ! callbacks->write_stdout) | ||||
| 333 | check_output (stdout(&__sF[1])); | ||||
| 334 | return 0; | ||||
| 335 | case 'L': | ||||
| 336 | /* Handle up to three -L options. */ | ||||
| 337 | if (tag_count < 3) | ||||
| 338 | { | ||||
| 339 | tag_strings[tag_count++] = optarg; | ||||
| 340 | break; | ||||
| 341 | } | ||||
| 342 | return try_help ("Too many labels were given. The limit is 3."); | ||||
| 343 | default: | ||||
| 344 | return try_help (0); | ||||
| 345 | } | ||||
| 346 | } | ||||
| 347 | |||||
| 348 | edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */ | ||||
| 349 | show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */ | ||||
| 350 | flagging |= ~incompat & merge; | ||||
| 351 | |||||
| 352 | if (incompat
| ||||
| 353 | || finalwrite & merge /* -i -m would rewrite input file. */ | ||||
| 354 | || (tag_count
| ||||
| 355 | return try_help ("incompatible options"); | ||||
| 356 | |||||
| 357 | if (argc - optind != 3) | ||||
| 358 | return try_help (argc - optind < 3 ? "missing operand" : "extra operand"); | ||||
| 359 | |||||
| 360 | file = &argv[optind]; | ||||
| 361 | |||||
| 362 | optind = optind_old; | ||||
| 363 | |||||
| 364 | for (i = tag_count; i < 3; i++) | ||||
| 365 | tag_strings[i] = file[i]; | ||||
| 366 | |||||
| 367 | /* Always compare file1 to file2, even if file2 is "-". | ||||
| 368 | This is needed for -mAeExX3. Using the file0 as | ||||
| 369 | the common file would produce wrong results, because if the | ||||
| 370 | file0-file1 diffs didn't line up with the file0-file2 diffs | ||||
| 371 | (which is entirely possible since we don't use diff's -n option), | ||||
| 372 | diff3 might report phantom changes from file1 to file2. */ | ||||
| 373 | /* Also try to compare file0 to file1 because this is the where | ||||
| 374 | changes are expected to come from. Diffing between these pairs | ||||
| 375 | of files is is most likely to return the intended changes. There | ||||
| 376 | can also be the same problem with phantom changes from file0 to | ||||
| 377 | file1. */ | ||||
| 378 | /* Historically, the default common file was file2. Ediff for emacs | ||||
| 379 | and possibly other applications, have therefore made file2 the | ||||
| 380 | ancestor. So, for compatibility, if this is simply a three | ||||
| 381 | way diff (not a merge or edscript) then use the old way with | ||||
| 382 | file2 as the common file. */ | ||||
| 383 | |||||
| 384 | { | ||||
| 385 | int common; | ||||
| 386 | if (edscript || merge ) | ||||
| 387 | { | ||||
| 388 | common = 1; | ||||
| 389 | } | ||||
| 390 | else | ||||
| 391 | { | ||||
| 392 | common = 2; | ||||
| 393 | } | ||||
| 394 | if (strcmp (file[common], "-") == 0) | ||||
| 395 | { | ||||
| 396 | /* Sigh. We've got standard input as the arg corresponding to | ||||
| 397 | the desired common file. We can't call diff twice on | ||||
| 398 | stdin. Use another arg as the common file instead. */ | ||||
| 399 | common = 3 - common; | ||||
| 400 | if (strcmp (file[0], "-") == 0 || strcmp (file[common], "-") == 0) | ||||
| 401 | { | ||||
| 402 | diff_error ("%s", "`-' specified for more than one input file", 0); | ||||
| 403 | return 2; | ||||
| 404 | } | ||||
| 405 | } | ||||
| 406 | |||||
| 407 | mapping[0] = 0; | ||||
| 408 | mapping[1] = 3 - common; | ||||
| 409 | mapping[2] = common; | ||||
| 410 | } | ||||
| 411 | |||||
| 412 | for (i = 0; i < 3; i++) | ||||
| 413 | rev_mapping[mapping[i]] = i; | ||||
| 414 | |||||
| 415 | for (i = 0; i < 3; i++) | ||||
| 416 | if (strcmp (file[i], "-") != 0) | ||||
| 417 | { | ||||
| 418 | if (stat (file[i], &statb) < 0) | ||||
| 419 | { | ||||
| 420 | perror_with_name (file[i]); | ||||
| 421 | return 2; | ||||
| 422 | } | ||||
| 423 | else if (S_ISDIR(statb.st_mode)((statb.st_mode & 0170000) == 0040000)) | ||||
| 424 | { | ||||
| 425 | diff_error ("%s: Is a directory", file[i], 0); | ||||
| 426 | return 2; | ||||
| 427 | } | ||||
| 428 | } | ||||
| 429 | |||||
| 430 | if (callbacks && callbacks->write_output) | ||||
| 431 | { | ||||
| 432 | if (out != NULL((void *)0)) | ||||
| 433 | { | ||||
| 434 | diff_error ("write callback with output file", 0, 0); | ||||
| 435 | return 2; | ||||
| 436 | } | ||||
| 437 | } | ||||
| 438 | else | ||||
| 439 | { | ||||
| 440 | if (out == NULL((void *)0)) | ||||
| 441 | outfile = stdout(&__sF[1]); | ||||
| 442 | else | ||||
| 443 | { | ||||
| 444 | outfile = fopen (out, "w"); | ||||
| 445 | if (outfile == NULL((void *)0)) | ||||
| 446 | { | ||||
| 447 | perror_with_name ("could not open output file"); | ||||
| 448 | return 2; | ||||
| 449 | } | ||||
| 450 | opened_file = 1; | ||||
| 451 | } | ||||
| 452 | } | ||||
| 453 | |||||
| 454 | /* Set the jump buffer, so that diff may abort execution without | ||||
| 455 | terminating the process. */ | ||||
| 456 | status = setjmp (diff3_abort_buf); | ||||
| 457 | if (status != 0) | ||||
| 458 | return status; | ||||
| 459 | |||||
| 460 | commonname = file[rev_mapping[FILEC2]]; | ||||
| 461 | thread1 = process_diff (file[rev_mapping[FILE11]], commonname, &last_block, | ||||
| 462 | &content1); | ||||
| 463 | /* What is the intention behind determining horizon_lines from first | ||||
| 464 | diff? I think it is better to use the same parameters for each | ||||
| 465 | diff so that equal differences in each diff will appear the | ||||
| 466 | same. */ | ||||
| 467 | /* | ||||
| 468 | if (thread1) | ||||
| 469 | for (i = 0; i < 2; i++) | ||||
| 470 | { | ||||
| 471 | horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i)); | ||||
| 472 | horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i)); | ||||
| 473 | } | ||||
| 474 | */ | ||||
| 475 | thread0 = process_diff (file[rev_mapping[FILE00]], commonname, &last_block, | ||||
| 476 | &content0); | ||||
| 477 | diff3 = make_3way_diff (thread0, thread1); | ||||
| 478 | if (edscript) | ||||
| 479 | conflicts_found | ||||
| 480 | = output_diff3_edscript (diff3, mapping, rev_mapping, | ||||
| 481 | tag_strings[0], tag_strings[1], tag_strings[2]); | ||||
| 482 | else if (merge) | ||||
| 483 | { | ||||
| 484 | FILE *mfp = fopen (file[rev_mapping[FILE00]], "r"); | ||||
| 485 | if (! mfp) | ||||
| 486 | diff3_perror_with_exit (file[rev_mapping[FILE00]]); | ||||
| 487 | conflicts_found = output_diff3_merge (mfp, diff3, mapping, rev_mapping, | ||||
| 488 | tag_strings[0], tag_strings[1], tag_strings[2]); | ||||
| 489 | if (ferror (mfp)(!__isthreaded ? (((mfp)->_flags & 0x0040) != 0) : (ferror )(mfp))) | ||||
| 490 | diff3_fatal ("read error"); | ||||
| 491 | if (fclose(mfp) != 0) | ||||
| 492 | perror_with_name (file[rev_mapping[FILE00]]); | ||||
| 493 | } | ||||
| 494 | else | ||||
| 495 | { | ||||
| 496 | output_diff3 (diff3, mapping, rev_mapping); | ||||
| 497 | conflicts_found = 0; | ||||
| 498 | } | ||||
| 499 | |||||
| 500 | free(content0); | ||||
| 501 | free(content1); | ||||
| 502 | free_diff3_blocks(diff3); | ||||
| 503 | |||||
| 504 | if (! callbacks || ! callbacks->write_output) | ||||
| 505 | check_output (outfile); | ||||
| 506 | |||||
| 507 | if (opened_file) | ||||
| 508 | if (fclose (outfile) != 0) | ||||
| 509 | perror_with_name ("close error on output file"); | ||||
| 510 | |||||
| 511 | return conflicts_found; | ||||
| 512 | } | ||||
| 513 | |||||
| 514 | static int | ||||
| 515 | try_help (reason) | ||||
| 516 | char const *reason; | ||||
| 517 | { | ||||
| 518 | if (reason) | ||||
| 519 | diff_error ("%s", reason, 0); | ||||
| 520 | diff_error ("Try `%s --help' for more information.", diff_program_name, 0); | ||||
| 521 | return 2; | ||||
| 522 | } | ||||
| 523 | |||||
| 524 | static void | ||||
| 525 | check_output (stream) | ||||
| 526 | FILE *stream; | ||||
| 527 | { | ||||
| 528 | if (ferror (stream)(!__isthreaded ? (((stream)->_flags & 0x0040) != 0) : ( ferror)(stream)) || fflush (stream) != 0) | ||||
| 529 | diff3_fatal ("write error"); | ||||
| 530 | } | ||||
| 531 | |||||
| 532 | /* | ||||
| 533 | * Explain, patiently and kindly, how to use this program. | ||||
| 534 | */ | ||||
| 535 | static void | ||||
| 536 | usage () | ||||
| 537 | { | ||||
| 538 | if (callbacks && callbacks->write_stdout) | ||||
| 539 | { | ||||
| 540 | (*callbacks->write_stdout) ("Usage: "); | ||||
| 541 | (*callbacks->write_stdout) (diff_program_name); | ||||
| 542 | (*callbacks->write_stdout) (" [OPTION]... MYFILE OLDFILE YOURFILE\n\n"); | ||||
| 543 | |||||
| 544 | (*callbacks->write_stdout) ("\ | ||||
| 545 | -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\ | ||||
| 546 | -E --show-overlap Output unmerged changes, bracketing conflicts.\n\ | ||||
| 547 | -A --show-all Output all changes, bracketing conflicts.\n\ | ||||
| 548 | -x --overlap-only Output overlapping changes.\n\ | ||||
| 549 | -X Output overlapping changes, bracketing them.\n\ | ||||
| 550 | -3 --easy-only Output unmerged nonoverlapping changes.\n\n"); | ||||
| 551 | (*callbacks->write_stdout) ("\ | ||||
| 552 | -m --merge Output merged file instead of ed script (default -A).\n\ | ||||
| 553 | -L LABEL --label=LABEL Use LABEL instead of file name.\n\ | ||||
| 554 | -i Append `w' and `q' commands to ed scripts.\n\ | ||||
| 555 | -a --text Treat all files as text.\n\ | ||||
| 556 | -T --initial-tab Make tabs line up by prepending a tab.\n\n"); | ||||
| 557 | (*callbacks->write_stdout) ("\ | ||||
| 558 | -v --version Output version info.\n\ | ||||
| 559 | --help Output this help.\n\n"); | ||||
| 560 | (*callbacks->write_stdout) ("If a FILE is `-', read standard input.\n"); | ||||
| 561 | } | ||||
| 562 | else | ||||
| 563 | { | ||||
| 564 | printf ("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n\n", diff_program_name); | ||||
| 565 | |||||
| 566 | printf ("%s", "\ | ||||
| 567 | -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\ | ||||
| 568 | -E --show-overlap Output unmerged changes, bracketing conflicts.\n\ | ||||
| 569 | -A --show-all Output all changes, bracketing conflicts.\n\ | ||||
| 570 | -x --overlap-only Output overlapping changes.\n\ | ||||
| 571 | -X Output overlapping changes, bracketing them.\n\ | ||||
| 572 | -3 --easy-only Output unmerged nonoverlapping changes.\n\n"); | ||||
| 573 | printf ("%s", "\ | ||||
| 574 | -m --merge Output merged file instead of ed script (default -A).\n\ | ||||
| 575 | -L LABEL --label=LABEL Use LABEL instead of file name.\n\ | ||||
| 576 | -i Append `w' and `q' commands to ed scripts.\n\ | ||||
| 577 | -a --text Treat all files as text.\n\ | ||||
| 578 | -T --initial-tab Make tabs line up by prepending a tab.\n\n"); | ||||
| 579 | printf ("%s", "\ | ||||
| 580 | -v --version Output version info.\n\ | ||||
| 581 | --help Output this help.\n\n"); | ||||
| 582 | printf ("If a FILE is `-', read standard input.\n"); | ||||
| 583 | } | ||||
| 584 | } | ||||
| 585 | |||||
| 586 | /* | ||||
| 587 | * Routines that combine the two diffs together into one. The | ||||
| 588 | * algorithm used follows: | ||||
| 589 | * | ||||
| 590 | * File2 is shared in common between the two diffs. | ||||
| 591 | * Diff02 is the diff between 0 and 2. | ||||
| 592 | * Diff12 is the diff between 1 and 2. | ||||
| 593 | * | ||||
| 594 | * 1) Find the range for the first block in File2. | ||||
| 595 | * a) Take the lowest of the two ranges (in File2) in the two | ||||
| 596 | * current blocks (one from each diff) as being the low | ||||
| 597 | * water mark. Assign the upper end of this block as | ||||
| 598 | * being the high water mark and move the current block up | ||||
| 599 | * one. Mark the block just moved over as to be used. | ||||
| 600 | * b) Check the next block in the diff that the high water | ||||
| 601 | * mark is *not* from. | ||||
| 602 | * | ||||
| 603 | * *If* the high water mark is above | ||||
| 604 | * the low end of the range in that block, | ||||
| 605 | * | ||||
| 606 | * mark that block as to be used and move the current | ||||
| 607 | * block up. Set the high water mark to the max of | ||||
| 608 | * the high end of this block and the current. Repeat b. | ||||
| 609 | * | ||||
| 610 | * 2) Find the corresponding ranges in File0 (from the blocks | ||||
| 611 | * in diff02; line per line outside of diffs) and in File1. | ||||
| 612 | * Create a diff3_block, reserving space as indicated by the ranges. | ||||
| 613 | * | ||||
| 614 | * 3) Copy all of the pointers for file2 in. At least for now, | ||||
| 615 | * do memcmp's between corresponding strings in the two diffs. | ||||
| 616 | * | ||||
| 617 | * 4) Copy all of the pointers for file0 and 1 in. Get what you | ||||
| 618 | * need from file2 (when there isn't a diff block, it's | ||||
| 619 | * identical to file2 within the range between diff blocks). | ||||
| 620 | * | ||||
| 621 | * 5) If the diff blocks you used came from only one of the two | ||||
| 622 | * strings of diffs, then that file (i.e. the one other than | ||||
| 623 | * the common file in that diff) is the odd person out. If you used | ||||
| 624 | * diff blocks from both sets, check to see if files 0 and 1 match: | ||||
| 625 | * | ||||
| 626 | * Same number of lines? If so, do a set of memcmp's (if a | ||||
| 627 | * memcmp matches; copy the pointer over; it'll be easier later | ||||
| 628 | * if you have to do any compares). If they match, 0 & 1 are | ||||
| 629 | * the same. If not, all three different. | ||||
| 630 | * | ||||
| 631 | * Then you do it again, until you run out of blocks. | ||||
| 632 | * | ||||
| 633 | */ | ||||
| 634 | |||||
| 635 | /* | ||||
| 636 | * This routine makes a three way diff (chain of diff3_block's) from two | ||||
| 637 | * two way diffs (chains of diff_block's). It is assumed that each of | ||||
| 638 | * the two diffs passed are onto the same file (i.e. that each of the | ||||
| 639 | * diffs were made "to" the same file). The three way diff pointer | ||||
| 640 | * returned will have numbering FILE0--the other file in diff02, | ||||
| 641 | * FILE1--the other file in diff12, and FILEC--the common file. | ||||
| 642 | */ | ||||
| 643 | static struct diff3_block * | ||||
| 644 | make_3way_diff (thread0, thread1) | ||||
| 645 | struct diff_block *thread0, *thread1; | ||||
| 646 | { | ||||
| 647 | /* | ||||
| 648 | * This routine works on the two diffs passed to it as threads. | ||||
| 649 | * Thread number 0 is diff02, thread number 1 is diff12. The USING | ||||
| 650 | * array is set to the base of the list of blocks to be used to | ||||
| 651 | * construct each block of the three way diff; if no blocks from a | ||||
| 652 | * particular thread are to be used, that element of the using array | ||||
| 653 | * is set to 0. The elements LAST_USING array are set to the last | ||||
| 654 | * elements on each of the using lists. | ||||
| 655 | * | ||||
| 656 | * The HIGH_WATER_MARK is set to the highest line number in the common file | ||||
| 657 | * described in any of the diffs in either of the USING lists. The | ||||
| 658 | * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK | ||||
| 659 | * and BASE_WATER_THREAD describe the lowest line number in the common file | ||||
| 660 | * described in any of the diffs in either of the USING lists. The | ||||
| 661 | * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was | ||||
| 662 | * taken. | ||||
| 663 | * | ||||
| 664 | * The HIGH_WATER_DIFF should always be equal to LAST_USING | ||||
| 665 | * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for | ||||
| 666 | * higher water, and should always be equal to | ||||
| 667 | * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread | ||||
| 668 | * in which the OTHER_DIFF is, and hence should always be equal to | ||||
| 669 | * HIGH_WATER_THREAD ^ 0x1. | ||||
| 670 | * | ||||
| 671 | * The variable LAST_DIFF is kept set to the last diff block produced | ||||
| 672 | * by this routine, for line correspondence purposes between that diff | ||||
| 673 | * and the one currently being worked on. It is initialized to | ||||
| 674 | * ZERO_DIFF before any blocks have been created. | ||||
| 675 | */ | ||||
| 676 | |||||
| 677 | struct diff_block | ||||
| 678 | *using[2], | ||||
| 679 | *last_using[2], | ||||
| 680 | *current[2]; | ||||
| 681 | |||||
| 682 | int | ||||
| 683 | high_water_mark; | ||||
| 684 | |||||
| 685 | int | ||||
| 686 | high_water_thread, | ||||
| 687 | base_water_thread, | ||||
| 688 | other_thread; | ||||
| 689 | |||||
| 690 | struct diff_block | ||||
| 691 | *high_water_diff, | ||||
| 692 | *other_diff; | ||||
| 693 | |||||
| 694 | struct diff3_block | ||||
| 695 | *result, | ||||
| 696 | *tmpblock, | ||||
| 697 | **result_end; | ||||
| 698 | |||||
| 699 | struct diff3_block const *last_diff3; | ||||
| 700 | |||||
| 701 | static struct diff3_block const zero_diff3 = { 0 }; | ||||
| 702 | |||||
| 703 | /* Initialization */ | ||||
| 704 | result = 0; | ||||
| 705 | result_end = &result; | ||||
| 706 | current[0] = thread0; current[1] = thread1; | ||||
| 707 | last_diff3 = &zero_diff3; | ||||
| 708 | |||||
| 709 | /* Sniff up the threads until we reach the end */ | ||||
| 710 | |||||
| 711 | while (current[0] || current[1]) | ||||
| 712 | { | ||||
| 713 | using[0] = using[1] = last_using[0] = last_using[1] = 0; | ||||
| 714 | |||||
| 715 | /* Setup low and high water threads, diffs, and marks. */ | ||||
| 716 | if (!current[0]) | ||||
| 717 | base_water_thread = 1; | ||||
| 718 | else if (!current[1]) | ||||
| 719 | base_water_thread = 0; | ||||
| 720 | else | ||||
| 721 | base_water_thread = | ||||
| 722 | (D_LOWLINE (current[0], FC)((current[0])->ranges[1][0]) > D_LOWLINE (current[1], FC)((current[1])->ranges[1][0])); | ||||
| 723 | |||||
| 724 | high_water_thread = base_water_thread; | ||||
| 725 | |||||
| 726 | high_water_diff = current[high_water_thread]; | ||||
| 727 | |||||
| 728 | #if 0 | ||||
| 729 | /* low and high waters start off same diff */ | ||||
| 730 | base_water_mark = D_LOWLINE (high_water_diff, FC)((high_water_diff)->ranges[1][0]); | ||||
| 731 | #endif | ||||
| 732 | |||||
| 733 | high_water_mark = D_HIGHLINE (high_water_diff, FC)((high_water_diff)->ranges[1][1]); | ||||
| 734 | |||||
| 735 | /* Make the diff you just got info from into the using class */ | ||||
| 736 | using[high_water_thread] | ||||
| 737 | = last_using[high_water_thread] | ||||
| 738 | = high_water_diff; | ||||
| 739 | current[high_water_thread] = high_water_diff->next; | ||||
| 740 | last_using[high_water_thread]->next = 0; | ||||
| 741 | |||||
| 742 | /* And mark the other diff */ | ||||
| 743 | other_thread = high_water_thread ^ 0x1; | ||||
| 744 | other_diff = current[other_thread]; | ||||
| 745 | |||||
| 746 | /* Shuffle up the ladder, checking the other diff to see if it | ||||
| 747 | needs to be incorporated. */ | ||||
| 748 | while (other_diff |
79.1 | 'other_diff' is null |
94 | Dereference of null pointer (loaded from variable 'f') |
33.1 | 'scan_diff' is < 'diff_limit' |
73.1 | 'scan_diff' is >= 'diff_limit' |
64.1 | 'dt' is not equal to ERROR |
68.1 | 'dt' is not equal to ADD |
71.1 | 'dt' is not equal to CHANGE |
72.1 | 'dt' is equal to DELETE |