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 |