File: | src/gnu/usr.bin/cvs/diff/diff3.c |
Warning: | line 966, column 30 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 |
95 | 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 |