| File: | src/gnu/usr.bin/cvs/diff/diff3.c |
| Warning: | line 1506, column 10 Array access results in a null pointer dereference |
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 |
81.1 | 'other_diff' is null |
132.1 | 'tmpblock' is non-null |
109.1 | 'u' is non-null |
124.1 | 'u' is null |
88.1 | 'numlines' is 1 |
93.1 | 'numlines' is 0 |
35.1 | 'scan_diff' is < 'diff_limit' |
75.1 | 'scan_diff' is >= 'diff_limit' |
66.1 | 'dt' is not equal to ERROR |
70.1 | 'dt' is not equal to ADD |
73.1 | 'dt' is not equal to CHANGE |
74.1 | 'dt' is equal to DELETE |
154.1 | 'oddoneout' is not equal to 1 |
160.1 | 'oddoneout' is not equal to 1 |
149.1 | 'i' is not equal to 'dontprint' |
158.1 | 'i' is equal to 'dontprint' |
166.1 | 'i' is not equal to 'dontprint' |
150.1 | 'lowt' is <= 'hight' |
170 | Array access results in a null pointer dereference |