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 |