File: | src/gnu/usr.bin/cvs/diff/diff3.c |
Warning: | line 775, column 8 Value stored to 'high_water_diff' is never read |
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 > 1 /* Ensure at most one of -AeExX3. */ |
353 | || finalwrite & merge /* -i -m would rewrite input file. */ |
354 | || (tag_count && ! flagging)) /* -L requires one of -AEX. */ |
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 |
749 | && D_LOWLINE (other_diff, FC)((other_diff)->ranges[1][0]) <= high_water_mark + 1) |
750 | { |
751 | |
752 | /* Incorporate this diff into the using list. Note that |
753 | this doesn't take it off the current list */ |
754 | if (using[other_thread]) |
755 | last_using[other_thread]->next = other_diff; |
756 | else |
757 | using[other_thread] = other_diff; |
758 | last_using[other_thread] = other_diff; |
759 | |
760 | /* Take it off the current list. Note that this following |
761 | code assumes that other_diff enters it equal to |
762 | current[high_water_thread ^ 0x1] */ |
763 | current[other_thread] = current[other_thread]->next; |
764 | other_diff->next = 0; |
765 | |
766 | /* Set the high_water stuff |
767 | If this comparison is equal, then this is the last pass |
768 | through this loop; since diff blocks within a given |
769 | thread cannot overlap, the high_water_mark will be |
770 | *below* the range_start of either of the next diffs. */ |
771 | |
772 | if (high_water_mark < D_HIGHLINE (other_diff, FC)((other_diff)->ranges[1][1])) |
773 | { |
774 | high_water_thread ^= 1; |
775 | high_water_diff = other_diff; |
Value stored to 'high_water_diff' is never read | |
776 | high_water_mark = D_HIGHLINE (other_diff, FC)((other_diff)->ranges[1][1]); |
777 | } |
778 | |
779 | /* Set the other diff */ |
780 | other_thread = high_water_thread ^ 0x1; |
781 | other_diff = current[other_thread]; |
782 | } |
783 | |
784 | /* The using lists contain a list of all of the blocks to be |
785 | included in this diff3_block. Create it. */ |
786 | |
787 | tmpblock = using_to_diff3_block (using, last_using, |
788 | base_water_thread, high_water_thread, |
789 | last_diff3); |
790 | free_diff_blocks(using[0]); |
791 | free_diff_blocks(using[1]); |
792 | |
793 | if (!tmpblock) |
794 | diff3_fatal ("internal error: screwup in format of diff blocks"); |
795 | |
796 | /* Put it on the list. */ |
797 | *result_end = tmpblock; |
798 | result_end = &tmpblock->next; |
799 | |
800 | /* Set up corresponding lines correctly. */ |
801 | last_diff3 = tmpblock; |
802 | } |
803 | return result; |
804 | } |
805 | |
806 | /* |
807 | * using_to_diff3_block: |
808 | * This routine takes two lists of blocks (from two separate diff |
809 | * threads) and puts them together into one diff3 block. |
810 | * It then returns a pointer to this diff3 block or 0 for failure. |
811 | * |
812 | * All arguments besides using are for the convenience of the routine; |
813 | * they could be derived from the using array. |
814 | * LAST_USING is a pair of pointers to the last blocks in the using |
815 | * structure. |
816 | * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest |
817 | * and highest line numbers for File0. |
818 | * last_diff3 contains the last diff produced in the calling routine. |
819 | * This is used for lines mappings which would still be identical to |
820 | * the state that diff ended in. |
821 | * |
822 | * A distinction should be made in this routine between the two diffs |
823 | * that are part of a normal two diff block, and the three diffs that |
824 | * are part of a diff3_block. |
825 | */ |
826 | static struct diff3_block * |
827 | using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3) |
828 | struct diff_block |
829 | *using[2], |
830 | *last_using[2]; |
831 | int low_thread, high_thread; |
832 | struct diff3_block const *last_diff3; |
833 | { |
834 | int low[2], high[2]; |
835 | struct diff3_block *result; |
836 | struct diff_block *ptr; |
837 | int d, i; |
838 | |
839 | /* Find the range in the common file. */ |
840 | int lowc = D_LOWLINE (using[low_thread], FC)((using[low_thread])->ranges[1][0]); |
841 | int highc = D_HIGHLINE (last_using[high_thread], FC)((last_using[high_thread])->ranges[1][1]); |
842 | |
843 | /* Find the ranges in the other files. |
844 | If using[d] is null, that means that the file to which that diff |
845 | refers is equivalent to the common file over this range. */ |
846 | |
847 | for (d = 0; d < 2; d++) |
848 | if (using[d]) |
849 | { |
850 | low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc)((lowc) - (((using[d]))->ranges[(1)][0]) + (((using[d]))-> ranges[(0)][0])); |
851 | high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc)((highc) - (((last_using[d]))->ranges[(1)][1]) + (((last_using [d]))->ranges[(0)][1])); |
852 | } |
853 | else |
854 | { |
855 | low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc)((lowc) - (((last_diff3))->ranges[(2)][1]) + (((last_diff3 ))->ranges[(0 + d)][1])); |
856 | high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc)((highc) - (((last_diff3))->ranges[(2)][1]) + (((last_diff3 ))->ranges[(0 + d)][1])); |
857 | } |
858 | |
859 | /* Create a block with the appropriate sizes */ |
860 | result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc); |
861 | |
862 | /* Copy information for the common file. |
863 | Return with a zero if any of the compares failed. */ |
864 | |
865 | for (d = 0; d < 2; d++) |
866 | for (ptr = using[d]; ptr; ptr = D_NEXT (ptr)((ptr)->next)) |
867 | { |
868 | int result_offset = D_LOWLINE (ptr, FC)((ptr)->ranges[1][0]) - lowc; |
869 | |
870 | if (!copy_stringlist (D_LINEARRAY (ptr, FC)((ptr)->lines[1]), |
871 | D_LENARRAY (ptr, FC)((ptr)->lengths[1]), |
872 | D_LINEARRAY (result, FILEC)((result)->lines[2]) + result_offset, |
873 | D_LENARRAY (result, FILEC)((result)->lengths[2]) + result_offset, |
874 | D_NUMLINES (ptr, FC)(((ptr)->ranges[1][1]) - ((ptr)->ranges[1][0]) + 1))) |
875 | return 0; |
876 | } |
877 | |
878 | /* Copy information for file d. First deal with anything that might be |
879 | before the first diff. */ |
880 | |
881 | for (d = 0; d < 2; d++) |
882 | { |
883 | struct diff_block *u = using[d]; |
884 | int lo = low[d], hi = high[d]; |
885 | |
886 | for (i = 0; |
887 | i + lo < (u ? D_LOWLINE (u, FO)((u)->ranges[0][0]) : hi + 1); |
888 | i++) |
889 | { |
890 | D_RELNUM (result, FILE0 + d, i)((result)->lines[0 + d][i]) = D_RELNUM (result, FILEC, i)((result)->lines[2][i]); |
891 | D_RELLEN (result, FILE0 + d, i)((result)->lengths[0 + d][i]) = D_RELLEN (result, FILEC, i)((result)->lengths[2][i]); |
892 | } |
893 | |
894 | for (ptr = u; ptr; ptr = D_NEXT (ptr)((ptr)->next)) |
895 | { |
896 | int result_offset = D_LOWLINE (ptr, FO)((ptr)->ranges[0][0]) - lo; |
897 | int linec; |
898 | |
899 | if (!copy_stringlist (D_LINEARRAY (ptr, FO)((ptr)->lines[0]), |
900 | D_LENARRAY (ptr, FO)((ptr)->lengths[0]), |
901 | D_LINEARRAY (result, FILE0 + d)((result)->lines[0 + d]) + result_offset, |
902 | D_LENARRAY (result, FILE0 + d)((result)->lengths[0 + d]) + result_offset, |
903 | D_NUMLINES (ptr, FO)(((ptr)->ranges[0][1]) - ((ptr)->ranges[0][0]) + 1))) |
904 | return 0; |
905 | |
906 | /* Catch the lines between here and the next diff */ |
907 | linec = D_HIGHLINE (ptr, FC)((ptr)->ranges[1][1]) + 1 - lowc; |
908 | for (i = D_HIGHLINE (ptr, FO)((ptr)->ranges[0][1]) + 1 - lo; |
909 | i < (D_NEXT (ptr)((ptr)->next) ? D_LOWLINE (D_NEXT (ptr), FO)((((ptr)->next))->ranges[0][0]) : hi + 1) - lo; |
910 | i++) |
911 | { |
912 | D_RELNUM (result, FILE0 + d, i)((result)->lines[0 + d][i]) = D_RELNUM (result, FILEC, linec)((result)->lines[2][linec]); |
913 | D_RELLEN (result, FILE0 + d, i)((result)->lengths[0 + d][i]) = D_RELLEN (result, FILEC, linec)((result)->lengths[2][linec]); |
914 | linec++; |
915 | } |
916 | } |
917 | } |
918 | |
919 | /* Set correspond */ |
920 | if (!using[0]) |
921 | D3_TYPE (result)((result)->correspond) = DIFF_2ND; |
922 | else if (!using[1]) |
923 | D3_TYPE (result)((result)->correspond) = DIFF_1ST; |
924 | else |
925 | { |
926 | int nl0 = D_NUMLINES (result, FILE0)(((result)->ranges[0][1]) - ((result)->ranges[0][0]) + 1 ); |
927 | int nl1 = D_NUMLINES (result, FILE1)(((result)->ranges[1][1]) - ((result)->ranges[1][0]) + 1 ); |
928 | |
929 | if (nl0 != nl1 |
930 | || !compare_line_list (D_LINEARRAY (result, FILE0)((result)->lines[0]), |
931 | D_LENARRAY (result, FILE0)((result)->lengths[0]), |
932 | D_LINEARRAY (result, FILE1)((result)->lines[1]), |
933 | D_LENARRAY (result, FILE1)((result)->lengths[1]), |
934 | nl0)) |
935 | D3_TYPE (result)((result)->correspond) = DIFF_ALL; |
936 | else |
937 | D3_TYPE (result)((result)->correspond) = DIFF_3RD; |
938 | } |
939 | |
940 | return result; |
941 | } |
942 | |
943 | /* |
944 | * This routine copies pointers from a list of strings to a different list |
945 | * of strings. If a spot in the second list is already filled, it |
946 | * makes sure that it is filled with the same string; if not it |
947 | * returns 0, the copy incomplete. |
948 | * Upon successful completion of the copy, it returns 1. |
949 | */ |
950 | static int |
951 | copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum) |
952 | char * const fromptrs[]; |
953 | char *toptrs[]; |
954 | size_t const fromlengths[]; |
955 | size_t tolengths[]; |
956 | int copynum; |
957 | { |
958 | register char * const *f = fromptrs; |
959 | register char **t = toptrs; |
960 | register size_t const *fl = fromlengths; |
961 | register size_t *tl = tolengths; |
962 | |
963 | while (copynum--) |
964 | { |
965 | if (*t) |
966 | { if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; } |
967 | else |
968 | { *t = *f ; *tl = *fl; } |
969 | |
970 | t++; f++; tl++; fl++; |
971 | } |
972 | return 1; |
973 | } |
974 | |
975 | /* |
976 | * Create a diff3_block, with ranges as specified in the arguments. |
977 | * Allocate the arrays for the various pointers (and zero them) based |
978 | * on the arguments passed. Return the block as a result. |
979 | */ |
980 | static struct diff3_block * |
981 | create_diff3_block (low0, high0, low1, high1, low2, high2) |
982 | register int low0, high0, low1, high1, low2, high2; |
983 | { |
984 | struct diff3_block *result = ALLOCATE (1, struct diff3_block)(struct diff3_block *) xmalloc ((1) * sizeof (struct diff3_block )); |
985 | int numlines; |
986 | |
987 | D3_TYPE (result)((result)->correspond) = ERROR; |
988 | D_NEXT (result)((result)->next) = 0; |
989 | |
990 | /* Assign ranges */ |
991 | D_LOWLINE (result, FILE0)((result)->ranges[0][0]) = low0; |
992 | D_HIGHLINE (result, FILE0)((result)->ranges[0][1]) = high0; |
993 | D_LOWLINE (result, FILE1)((result)->ranges[1][0]) = low1; |
994 | D_HIGHLINE (result, FILE1)((result)->ranges[1][1]) = high1; |
995 | D_LOWLINE (result, FILE2)((result)->ranges[2][0]) = low2; |
996 | D_HIGHLINE (result, FILE2)((result)->ranges[2][1]) = high2; |
997 | |
998 | /* Allocate and zero space */ |
999 | numlines = D_NUMLINES (result, FILE0)(((result)->ranges[0][1]) - ((result)->ranges[0][0]) + 1 ); |
1000 | if (numlines) |
1001 | { |
1002 | D_LINEARRAY (result, FILE0)((result)->lines[0]) = ALLOCATE (numlines, char *)(char * *) xmalloc ((numlines) * sizeof (char *)); |
1003 | D_LENARRAY (result, FILE0)((result)->lengths[0]) = ALLOCATE (numlines, size_t)(size_t *) xmalloc ((numlines) * sizeof (size_t)); |
1004 | bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)))memset (((result)->lines[0]), 0, (numlines * sizeof (char * ))); |
1005 | bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (size_t)))memset (((result)->lengths[0]), 0, (numlines * sizeof (size_t ))); |
1006 | } |
1007 | else |
1008 | { |
1009 | D_LINEARRAY (result, FILE0)((result)->lines[0]) = 0; |
1010 | D_LENARRAY (result, FILE0)((result)->lengths[0]) = 0; |
1011 | } |
1012 | |
1013 | numlines = D_NUMLINES (result, FILE1)(((result)->ranges[1][1]) - ((result)->ranges[1][0]) + 1 ); |
1014 | if (numlines) |
1015 | { |
1016 | D_LINEARRAY (result, FILE1)((result)->lines[1]) = ALLOCATE (numlines, char *)(char * *) xmalloc ((numlines) * sizeof (char *)); |
1017 | D_LENARRAY (result, FILE1)((result)->lengths[1]) = ALLOCATE (numlines, size_t)(size_t *) xmalloc ((numlines) * sizeof (size_t)); |
1018 | bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)))memset (((result)->lines[1]), 0, (numlines * sizeof (char * ))); |
1019 | bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (size_t)))memset (((result)->lengths[1]), 0, (numlines * sizeof (size_t ))); |
1020 | } |
1021 | else |
1022 | { |
1023 | D_LINEARRAY (result, FILE1)((result)->lines[1]) = 0; |
1024 | D_LENARRAY (result, FILE1)((result)->lengths[1]) = 0; |
1025 | } |
1026 | |
1027 | numlines = D_NUMLINES (result, FILE2)(((result)->ranges[2][1]) - ((result)->ranges[2][0]) + 1 ); |
1028 | if (numlines) |
1029 | { |
1030 | D_LINEARRAY (result, FILE2)((result)->lines[2]) = ALLOCATE (numlines, char *)(char * *) xmalloc ((numlines) * sizeof (char *)); |
1031 | D_LENARRAY (result, FILE2)((result)->lengths[2]) = ALLOCATE (numlines, size_t)(size_t *) xmalloc ((numlines) * sizeof (size_t)); |
1032 | bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)))memset (((result)->lines[2]), 0, (numlines * sizeof (char * ))); |
1033 | bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (size_t)))memset (((result)->lengths[2]), 0, (numlines * sizeof (size_t ))); |
1034 | } |
1035 | else |
1036 | { |
1037 | D_LINEARRAY (result, FILE2)((result)->lines[2]) = 0; |
1038 | D_LENARRAY (result, FILE2)((result)->lengths[2]) = 0; |
1039 | } |
1040 | |
1041 | /* Return */ |
1042 | return result; |
1043 | } |
1044 | |
1045 | /* |
1046 | * Compare two lists of lines of text. |
1047 | * Return 1 if they are equivalent, 0 if not. |
1048 | */ |
1049 | static int |
1050 | compare_line_list (list1, lengths1, list2, lengths2, nl) |
1051 | char * const list1[], * const list2[]; |
1052 | size_t const lengths1[], lengths2[]; |
1053 | int nl; |
1054 | { |
1055 | char |
1056 | * const *l1 = list1, |
1057 | * const *l2 = list2; |
1058 | size_t const |
1059 | *lgths1 = lengths1, |
1060 | *lgths2 = lengths2; |
1061 | |
1062 | while (nl--) |
1063 | if (!*l1 || !*l2 || *lgths1 != *lgths2++ |
1064 | || memcmp (*l1++, *l2++, *lgths1++)) |
1065 | return 0; |
1066 | return 1; |
1067 | } |
1068 | |
1069 | /* |
1070 | * Routines to input and parse two way diffs. |
1071 | */ |
1072 | |
1073 | extern char **environ; |
1074 | |
1075 | static struct diff_block * |
1076 | process_diff (filea, fileb, last_block, diff_contents) |
1077 | char const *filea, *fileb; |
1078 | struct diff_block **last_block; |
1079 | char **diff_contents; |
1080 | { |
1081 | char *diff_limit; |
1082 | char *scan_diff; |
1083 | enum diff_type dt; |
1084 | int i; |
1085 | struct diff_block *block_list, **block_list_end, *bptr; |
1086 | |
1087 | diff_limit = read_diff (filea, fileb, diff_contents); |
1088 | scan_diff = *diff_contents; |
1089 | block_list_end = &block_list; |
1090 | bptr = 0; /* Pacify `gcc -W'. */ |
1091 | |
1092 | while (scan_diff < diff_limit) |
1093 | { |
1094 | bptr = ALLOCATE (1, struct diff_block)(struct diff_block *) xmalloc ((1) * sizeof (struct diff_block )); |
1095 | bptr->lines[0] = bptr->lines[1] = 0; |
1096 | bptr->lengths[0] = bptr->lengths[1] = 0; |
1097 | |
1098 | dt = process_diff_control (&scan_diff, bptr); |
1099 | if (dt == ERROR || *scan_diff != '\n') |
1100 | { |
1101 | char *serr; |
1102 | |
1103 | for (serr = scan_diff; *serr != '\n'; serr++) |
1104 | ; |
1105 | *serr = '\0'; |
1106 | diff_error ("diff error: %s", scan_diff, 0); |
1107 | *serr = '\n'; |
1108 | DIFF3_ABORT (2)longjmp(diff3_abort_buf, 2); |
1109 | } |
1110 | scan_diff++; |
1111 | |
1112 | /* Force appropriate ranges to be null, if necessary */ |
1113 | switch (dt) |
1114 | { |
1115 | case ADD: |
1116 | bptr->ranges[0][0]++; |
1117 | break; |
1118 | case DELETE: |
1119 | bptr->ranges[1][0]++; |
1120 | break; |
1121 | case CHANGE: |
1122 | break; |
1123 | default: |
1124 | diff3_fatal ("internal error: invalid diff type in process_diff"); |
1125 | break; |
1126 | } |
1127 | |
1128 | /* Allocate space for the pointers for the lines from filea, and |
1129 | parcel them out among these pointers */ |
1130 | if (dt != ADD) |
1131 | { |
1132 | int numlines = D_NUMLINES (bptr, 0)(((bptr)->ranges[0][1]) - ((bptr)->ranges[0][0]) + 1); |
1133 | bptr->lines[0] = ALLOCATE (numlines, char *)(char * *) xmalloc ((numlines) * sizeof (char *)); |
1134 | bptr->lengths[0] = ALLOCATE (numlines, size_t)(size_t *) xmalloc ((numlines) * sizeof (size_t)); |
1135 | for (i = 0; i < numlines; i++) |
1136 | scan_diff = scan_diff_line (scan_diff, |
1137 | &(bptr->lines[0][i]), |
1138 | &(bptr->lengths[0][i]), |
1139 | diff_limit, |
1140 | '<'); |
1141 | } |
1142 | |
1143 | /* Get past the separator for changes */ |
1144 | if (dt == CHANGE) |
1145 | { |
1146 | if (strncmp (scan_diff, "---\n", 4)) |
1147 | diff3_fatal ("invalid diff format; invalid change separator"); |
1148 | scan_diff += 4; |
1149 | } |
1150 | |
1151 | /* Allocate space for the pointers for the lines from fileb, and |
1152 | parcel them out among these pointers */ |
1153 | if (dt != DELETE) |
1154 | { |
1155 | int numlines = D_NUMLINES (bptr, 1)(((bptr)->ranges[1][1]) - ((bptr)->ranges[1][0]) + 1); |
1156 | bptr->lines[1] = ALLOCATE (numlines, char *)(char * *) xmalloc ((numlines) * sizeof (char *)); |
1157 | bptr->lengths[1] = ALLOCATE (numlines, size_t)(size_t *) xmalloc ((numlines) * sizeof (size_t)); |
1158 | for (i = 0; i < numlines; i++) |
1159 | scan_diff = scan_diff_line (scan_diff, |
1160 | &(bptr->lines[1][i]), |
1161 | &(bptr->lengths[1][i]), |
1162 | diff_limit, |
1163 | '>'); |
1164 | } |
1165 | |
1166 | /* Place this block on the blocklist. */ |
1167 | *block_list_end = bptr; |
1168 | block_list_end = &bptr->next; |
1169 | } |
1170 | |
1171 | *block_list_end = 0; |
1172 | *last_block = bptr; |
1173 | return block_list; |
1174 | } |
1175 | |
1176 | /* |
1177 | * This routine will parse a normal format diff control string. It |
1178 | * returns the type of the diff (ERROR if the format is bad). All of |
1179 | * the other important information is filled into to the structure |
1180 | * pointed to by db, and the string pointer (whose location is passed |
1181 | * to this routine) is updated to point beyond the end of the string |
1182 | * parsed. Note that only the ranges in the diff_block will be set by |
1183 | * this routine. |
1184 | * |
1185 | * If some specific pair of numbers has been reduced to a single |
1186 | * number, then both corresponding numbers in the diff block are set |
1187 | * to that number. In general these numbers are interpetted as ranges |
1188 | * inclusive, unless being used by the ADD or DELETE commands. It is |
1189 | * assumed that these will be special cased in a superior routine. |
1190 | */ |
1191 | |
1192 | static enum diff_type |
1193 | process_diff_control (string, db) |
1194 | char **string; |
1195 | struct diff_block *db; |
1196 | { |
1197 | char *s = *string; |
1198 | int holdnum; |
1199 | enum diff_type type; |
1200 | |
1201 | /* These macros are defined here because they can use variables |
1202 | defined in this function. Don't try this at home kids, we're |
1203 | trained professionals! |
1204 | |
1205 | Also note that SKIPWHITE only recognizes tabs and spaces, and |
1206 | that READNUM can only read positive, integral numbers */ |
1207 | |
1208 | #define SKIPWHITE(s){ while (*s == ' ' || *s == '\t') s++; } { while (*s == ' ' || *s == '\t') s++; } |
1209 | #define READNUM(s, num){ unsigned char c = *s; if (!((unsigned) (c) - '0' <= 9)) return ERROR; holdnum = 0; do { holdnum = (c - '0' + holdnum * 10); } while (((unsigned) (c = *++s) - '0' <= 9)); (num) = holdnum ; } \ |
1210 | { unsigned char c = *s; if (!ISDIGIT (c)((unsigned) (c) - '0' <= 9)) return ERROR; holdnum = 0; \ |
1211 | do { holdnum = (c - '0' + holdnum * 10); } \ |
1212 | while (ISDIGIT (c = *++s)((unsigned) (c = *++s) - '0' <= 9)); (num) = holdnum; } |
1213 | |
1214 | /* Read first set of digits */ |
1215 | SKIPWHITE (s){ while (*s == ' ' || *s == '\t') s++; }; |
1216 | READNUM (s, db->ranges[0][START]){ unsigned char c = *s; if (!((unsigned) (c) - '0' <= 9)) return ERROR; holdnum = 0; do { holdnum = (c - '0' + holdnum * 10); } while (((unsigned) (c = *++s) - '0' <= 9)); (db->ranges [0][0]) = holdnum; }; |
1217 | |
1218 | /* Was that the only digit? */ |
1219 | SKIPWHITE (s){ while (*s == ' ' || *s == '\t') s++; }; |
1220 | if (*s == ',') |
1221 | { |
1222 | /* Get the next digit */ |
1223 | s++; |
1224 | READNUM (s, db->ranges[0][END]){ unsigned char c = *s; if (!((unsigned) (c) - '0' <= 9)) return ERROR; holdnum = 0; do { holdnum = (c - '0' + holdnum * 10); } while (((unsigned) (c = *++s) - '0' <= 9)); (db->ranges [0][1]) = holdnum; }; |
1225 | } |
1226 | else |
1227 | db->ranges[0][END1] = db->ranges[0][START0]; |
1228 | |
1229 | /* Get the letter */ |
1230 | SKIPWHITE (s){ while (*s == ' ' || *s == '\t') s++; }; |
1231 | switch (*s) |
1232 | { |
1233 | case 'a': |
1234 | type = ADD; |
1235 | break; |
1236 | case 'c': |
1237 | type = CHANGE; |
1238 | break; |
1239 | case 'd': |
1240 | type = DELETE; |
1241 | break; |
1242 | default: |
1243 | return ERROR; /* Bad format */ |
1244 | } |
1245 | s++; /* Past letter */ |
1246 | |
1247 | /* Read second set of digits */ |
1248 | SKIPWHITE (s){ while (*s == ' ' || *s == '\t') s++; }; |
1249 | READNUM (s, db->ranges[1][START]){ unsigned char c = *s; if (!((unsigned) (c) - '0' <= 9)) return ERROR; holdnum = 0; do { holdnum = (c - '0' + holdnum * 10); } while (((unsigned) (c = *++s) - '0' <= 9)); (db->ranges [1][0]) = holdnum; }; |
1250 | |
1251 | /* Was that the only digit? */ |
1252 | SKIPWHITE (s){ while (*s == ' ' || *s == '\t') s++; }; |
1253 | if (*s == ',') |
1254 | { |
1255 | /* Get the next digit */ |
1256 | s++; |
1257 | READNUM (s, db->ranges[1][END]){ unsigned char c = *s; if (!((unsigned) (c) - '0' <= 9)) return ERROR; holdnum = 0; do { holdnum = (c - '0' + holdnum * 10); } while (((unsigned) (c = *++s) - '0' <= 9)); (db->ranges [1][1]) = holdnum; }; |
1258 | SKIPWHITE (s){ while (*s == ' ' || *s == '\t') s++; }; /* To move to end */ |
1259 | } |
1260 | else |
1261 | db->ranges[1][END1] = db->ranges[1][START0]; |
1262 | |
1263 | *string = s; |
1264 | return type; |
1265 | } |
1266 | |
1267 | static char * |
1268 | read_diff (filea, fileb, output_placement) |
1269 | char const *filea, *fileb; |
1270 | char **output_placement; |
1271 | { |
1272 | char *diff_result; |
1273 | size_t bytes, current_chunk_size, total; |
1274 | int fd, wstatus; |
1275 | struct stat pipestat; |
1276 | FILE *outfile_hold; |
1277 | const struct diff_callbacks *callbacks_hold; |
1278 | struct diff_callbacks my_callbacks; |
1279 | struct diff_callbacks *my_callbacks_arg; |
1280 | |
1281 | /* 302 / 1000 is log10(2.0) rounded up. Subtract 1 for the sign bit; |
1282 | add 1 for integer division truncation; add 1 more for a minus sign. */ |
1283 | #define INT_STRLEN_BOUND(type)((sizeof(type)*8 - 1) * 302 / 1000 + 2) ((sizeof(type)*CHAR_BIT8 - 1) * 302 / 1000 + 2) |
1284 | |
1285 | char const *argv[7]; |
1286 | char horizon_arg[17 + INT_STRLEN_BOUND (int)((sizeof(int)*8 - 1) * 302 / 1000 + 2)]; |
1287 | char const **ap; |
1288 | char *diffout; |
1289 | |
1290 | ap = argv; |
1291 | *ap++ = "diff"; |
1292 | if (always_text) |
1293 | *ap++ = "-a"; |
1294 | sprintf (horizon_arg, "--horizon-lines=%d", horizon_lines); |
1295 | *ap++ = horizon_arg; |
1296 | *ap++ = "--"; |
1297 | *ap++ = filea; |
1298 | *ap++ = fileb; |
1299 | *ap = 0; |
1300 | |
1301 | diffout = cvs_temp_name (); |
1302 | |
1303 | outfile_hold = outfile; |
1304 | callbacks_hold = callbacks; |
1305 | |
1306 | /* We want to call diff_run preserving any stdout and stderr |
1307 | callbacks, but discarding any callbacks to handle file output, |
1308 | since we want the file output to go to our temporary file. |
1309 | FIXME: We should use callbacks to just read it into a memory |
1310 | buffer; that's we do with the temporary file just below anyhow. */ |
1311 | if (callbacks == NULL((void *)0)) |
1312 | my_callbacks_arg = NULL((void *)0); |
1313 | else |
1314 | { |
1315 | my_callbacks = *callbacks; |
1316 | my_callbacks.write_output = NULL((void *)0); |
1317 | my_callbacks.flush_output = NULL((void *)0); |
1318 | my_callbacks_arg = &my_callbacks; |
1319 | } |
1320 | |
1321 | wstatus = diff_run (ap - argv, (char **) argv, diffout, my_callbacks_arg); |
1322 | |
1323 | outfile = outfile_hold; |
1324 | callbacks = callbacks_hold; |
1325 | |
1326 | if (wstatus == 2) |
1327 | diff3_fatal ("subsidiary diff failed"); |
1328 | |
1329 | if (-1 == (fd = open (diffout, O_RDONLY0x0000))) |
1330 | diff3_fatal ("could not open temporary diff file"); |
1331 | |
1332 | current_chunk_size = 8 * 1024; |
1333 | if (fstat (fd, &pipestat) == 0) |
1334 | current_chunk_size = max (current_chunk_size, STAT_BLOCKSIZE (pipestat))((current_chunk_size) >= ((pipestat).st_blksize) ? (current_chunk_size ) : ((pipestat).st_blksize)); |
1335 | |
1336 | diff_result = xmalloc (current_chunk_size); |
1337 | total = 0; |
1338 | do { |
1339 | bytes = myread (fd, |
1340 | diff_result + total, |
1341 | current_chunk_size - total); |
1342 | total += bytes; |
1343 | if (total == current_chunk_size) |
1344 | { |
1345 | if (current_chunk_size < 2 * current_chunk_size) |
1346 | current_chunk_size = 2 * current_chunk_size; |
1347 | else if (current_chunk_size < (size_t) -1) |
1348 | current_chunk_size = (size_t) -1; |
1349 | else |
1350 | diff3_fatal ("files are too large to fit into memory"); |
1351 | diff_result = xrealloc (diff_result, (current_chunk_size *= 2)); |
1352 | } |
1353 | } while (bytes); |
1354 | |
1355 | if (total != 0 && diff_result[total-1] != '\n') |
1356 | diff3_fatal ("invalid diff format; incomplete last line"); |
1357 | |
1358 | *output_placement = diff_result; |
1359 | |
1360 | if (close (fd) != 0) |
1361 | diff3_perror_with_exit ("pipe close"); |
1362 | unlink (diffout); |
1363 | |
1364 | return diff_result + total; |
1365 | } |
1366 | |
1367 | |
1368 | /* |
1369 | * Scan a regular diff line (consisting of > or <, followed by a |
1370 | * space, followed by text (including nulls) up to a newline. |
1371 | * |
1372 | * This next routine began life as a macro and many parameters in it |
1373 | * are used as call-by-reference values. |
1374 | */ |
1375 | static char * |
1376 | scan_diff_line (scan_ptr, set_start, set_length, limit, leadingchar) |
1377 | char *scan_ptr, **set_start; |
1378 | size_t *set_length; |
1379 | char *limit; |
1380 | int leadingchar; |
1381 | { |
1382 | char *line_ptr; |
1383 | |
1384 | if (!(scan_ptr[0] == leadingchar |
1385 | && scan_ptr[1] == ' ')) |
1386 | diff3_fatal ("invalid diff format; incorrect leading line chars"); |
1387 | |
1388 | *set_start = line_ptr = scan_ptr + 2; |
1389 | while (*line_ptr++ != '\n') |
1390 | ; |
1391 | |
1392 | /* Include newline if the original line ended in a newline, |
1393 | or if an edit script is being generated. |
1394 | Copy any missing newline message to stderr if an edit script is being |
1395 | generated, because edit scripts cannot handle missing newlines. |
1396 | Return the beginning of the next line. */ |
1397 | *set_length = line_ptr - *set_start; |
1398 | if (line_ptr < limit && *line_ptr == '\\') |
1399 | { |
1400 | if (! edscript) |
1401 | { |
1402 | --*set_length; |
1403 | line_ptr++; |
1404 | while (*line_ptr++ != '\n') |
1405 | ; |
1406 | } |
1407 | else |
1408 | { |
1409 | char *serr; |
1410 | |
1411 | line_ptr++; |
1412 | serr = line_ptr; |
1413 | while (*line_ptr++ != '\n') |
1414 | ; |
1415 | line_ptr[-1] = '\0'; |
1416 | diff_error ("%s", serr, 0); |
1417 | line_ptr[-1] = '\n'; |
1418 | } |
1419 | } |
1420 | |
1421 | return line_ptr; |
1422 | } |
1423 | |
1424 | /* |
1425 | * This routine outputs a three way diff passed as a list of |
1426 | * diff3_block's. |
1427 | * The argument MAPPING is indexed by external file number (in the |
1428 | * argument list) and contains the internal file number (from the |
1429 | * diff passed). This is important because the user expects his |
1430 | * outputs in terms of the argument list number, and the diff passed |
1431 | * may have been done slightly differently (if the last argument |
1432 | * was "-", for example). |
1433 | * REV_MAPPING is the inverse of MAPPING. |
1434 | */ |
1435 | static void |
1436 | output_diff3 (diff, mapping, rev_mapping) |
1437 | struct diff3_block *diff; |
1438 | int const mapping[3], rev_mapping[3]; |
1439 | { |
1440 | int i; |
1441 | int oddoneout; |
1442 | char *cp; |
1443 | struct diff3_block *ptr; |
1444 | int line; |
1445 | size_t length; |
1446 | int dontprint; |
1447 | static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */ |
1448 | char const *line_prefix = tab_align_flag ? "\t" : " "; |
1449 | |
1450 | for (ptr = diff; ptr; ptr = D_NEXT (ptr)((ptr)->next)) |
1451 | { |
1452 | char x[2]; |
1453 | |
1454 | switch (ptr->correspond) |
1455 | { |
1456 | case DIFF_ALL: |
1457 | x[0] = '\0'; |
1458 | dontprint = 3; /* Print them all */ |
1459 | oddoneout = 3; /* Nobody's odder than anyone else */ |
1460 | break; |
1461 | case DIFF_1ST: |
1462 | case DIFF_2ND: |
1463 | case DIFF_3RD: |
1464 | oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST]; |
1465 | |
1466 | x[0] = oddoneout + '1'; |
1467 | x[1] = '\0'; |
1468 | dontprint = oddoneout==0; |
1469 | break; |
1470 | default: |
1471 | diff3_fatal ("internal error: invalid diff type passed to output"); |
1472 | } |
1473 | printf_output ("====%s\n", x); |
1474 | |
1475 | /* Go 0, 2, 1 if the first and third outputs are equivalent. */ |
1476 | for (i = 0; i < 3; |
1477 | i = (oddoneout == 1 ? skew_increment[i] : i + 1)) |
1478 | { |
1479 | int realfile = mapping[i]; |
1480 | int |
1481 | lowt = D_LOWLINE (ptr, realfile)((ptr)->ranges[realfile][0]), |
1482 | hight = D_HIGHLINE (ptr, realfile)((ptr)->ranges[realfile][1]); |
1483 | |
1484 | printf_output ("%d:", i + 1); |
1485 | switch (lowt - hight) |
1486 | { |
1487 | case 1: |
1488 | printf_output ("%da\n", lowt - 1); |
1489 | break; |
1490 | case 0: |
1491 | printf_output ("%dc\n", lowt); |
1492 | break; |
1493 | default: |
1494 | printf_output ("%d,%dc\n", lowt, hight); |
1495 | break; |
1496 | } |
1497 | |
1498 | if (i == dontprint) continue; |
1499 | |
1500 | if (lowt <= hight) |
1501 | { |
1502 | line = 0; |
1503 | do |
1504 | { |
1505 | printf_output ("%s", line_prefix); |
1506 | cp = D_RELNUM (ptr, realfile, line)((ptr)->lines[realfile][line]); |
1507 | length = D_RELLEN (ptr, realfile, line)((ptr)->lengths[realfile][line]); |
1508 | write_output (cp, length); |
1509 | } |
1510 | while (++line < hight - lowt + 1); |
1511 | if (cp[length - 1] != '\n') |
1512 | printf_output ("\n\\ No newline at end of file\n"); |
1513 | } |
1514 | } |
1515 | } |
1516 | } |
1517 | |
1518 | |
1519 | /* |
1520 | * Output the lines of B taken from FILENUM. |
1521 | * Double any initial '.'s; yield nonzero if any initial '.'s were doubled. |
1522 | */ |
1523 | static int |
1524 | dotlines (b, filenum) |
1525 | struct diff3_block *b; |
1526 | int filenum; |
1527 | { |
1528 | int i; |
1529 | int leading_dot = 0; |
1530 | |
1531 | for (i = 0; |
1532 | i < D_NUMLINES (b, filenum)(((b)->ranges[filenum][1]) - ((b)->ranges[filenum][0]) + 1); |
1533 | i++) |
1534 | { |
1535 | char *line = D_RELNUM (b, filenum, i)((b)->lines[filenum][i]); |
1536 | if (line[0] == '.') |
1537 | { |
1538 | leading_dot = 1; |
1539 | write_output (".", 1); |
1540 | } |
1541 | write_output (line, D_RELLEN (b, filenum, i)((b)->lengths[filenum][i])); |
1542 | } |
1543 | |
1544 | return leading_dot; |
1545 | } |
1546 | |
1547 | /* |
1548 | * Output to OUTPUTFILE a '.' line. If LEADING_DOT is nonzero, |
1549 | * also output a command that removes initial '.'s |
1550 | * starting with line START and continuing for NUM lines. |
1551 | */ |
1552 | static void |
1553 | undotlines (leading_dot, start, num) |
1554 | int leading_dot, start, num; |
1555 | { |
1556 | write_output (".\n", 2); |
1557 | if (leading_dot) { |
1558 | if (num == 1) |
1559 | printf_output ("%ds/^\\.//\n", start); |
1560 | else |
1561 | printf_output ("%d,%ds/^\\.//\n", start, start + num - 1); |
1562 | } |
1563 | } |
1564 | |
1565 | /* |
1566 | * This routine outputs a diff3 set of blocks as an ed script. This |
1567 | * script applies the changes between file's 2 & 3 to file 1. It |
1568 | * takes the precise format of the ed script to be output from global |
1569 | * variables set during options processing. Note that it does |
1570 | * destructive things to the set of diff3 blocks it is passed; it |
1571 | * reverses their order (this gets around the problems involved with |
1572 | * changing line numbers in an ed script). |
1573 | * |
1574 | * Note that this routine has the same problem of mapping as the last |
1575 | * one did; the variable MAPPING maps from file number according to |
1576 | * the argument list to file number according to the diff passed. All |
1577 | * files listed below are in terms of the argument list. |
1578 | * REV_MAPPING is the inverse of MAPPING. |
1579 | * |
1580 | * The arguments FILE0, FILE1 and FILE2 are the strings to print |
1581 | * as the names of the three files. These may be the actual names, |
1582 | * or may be the arguments specified with -L. |
1583 | * |
1584 | * Returns 1 if conflicts were found. |
1585 | */ |
1586 | |
1587 | static int |
1588 | output_diff3_edscript (diff, mapping, rev_mapping, file0, file1, file2) |
1589 | struct diff3_block *diff; |
1590 | int const mapping[3], rev_mapping[3]; |
1591 | char const *file0, *file1, *file2; |
1592 | { |
1593 | int leading_dot; |
1594 | int conflicts_found = 0, conflict; |
1595 | struct diff3_block *b; |
1596 | |
1597 | for (b = reverse_diff3_blocklist (diff); b; b = b->next) |
1598 | { |
1599 | /* Must do mapping correctly. */ |
1600 | enum diff_type type |
1601 | = ((b->correspond == DIFF_ALL) ? |
1602 | DIFF_ALL : |
1603 | ((enum diff_type) |
1604 | (((int) DIFF_1ST) |
1605 | + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); |
1606 | |
1607 | /* If we aren't supposed to do this output block, skip it. */ |
1608 | switch (type) |
1609 | { |
1610 | default: continue; |
1611 | case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break; |
1612 | case DIFF_3RD: if (overlap_only) continue; conflict = 0; break; |
1613 | case DIFF_ALL: if (simple_only) continue; conflict = flagging; break; |
1614 | } |
1615 | |
1616 | if (conflict) |
1617 | { |
1618 | conflicts_found = 1; |
1619 | |
1620 | |
1621 | /* Mark end of conflict. */ |
1622 | |
1623 | printf_output ("%da\n", D_HIGHLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][1])); |
1624 | leading_dot = 0; |
1625 | if (type == DIFF_ALL) |
1626 | { |
1627 | if (show_2nd) |
1628 | { |
1629 | /* Append lines from FILE1. */ |
1630 | printf_output ("||||||| %s\n", file1); |
1631 | leading_dot = dotlines (b, mapping[FILE11]); |
1632 | } |
1633 | /* Append lines from FILE2. */ |
1634 | printf_output ("=======\n"); |
1635 | leading_dot |= dotlines (b, mapping[FILE22]); |
1636 | } |
1637 | printf_output (">>>>>>> %s\n", file2); |
1638 | undotlines (leading_dot, |
1639 | D_HIGHLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][1]) + 2, |
1640 | (D_NUMLINES (b, mapping[FILE1])(((b)->ranges[mapping[1]][1]) - ((b)->ranges[mapping[1] ][0]) + 1) |
1641 | + D_NUMLINES (b, mapping[FILE2])(((b)->ranges[mapping[2]][1]) - ((b)->ranges[mapping[2] ][0]) + 1) + 1)); |
1642 | |
1643 | |
1644 | /* Mark start of conflict. */ |
1645 | |
1646 | printf_output ("%da\n<<<<<<< %s\n", |
1647 | D_LOWLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][0]) - 1, |
1648 | type == DIFF_ALL ? file0 : file1); |
1649 | leading_dot = 0; |
1650 | if (type == DIFF_2ND) |
1651 | { |
1652 | /* Prepend lines from FILE1. */ |
1653 | leading_dot = dotlines (b, mapping[FILE11]); |
1654 | printf_output ("=======\n"); |
1655 | } |
1656 | undotlines (leading_dot, |
1657 | D_LOWLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][0]) + 1, |
1658 | D_NUMLINES (b, mapping[FILE1])(((b)->ranges[mapping[1]][1]) - ((b)->ranges[mapping[1] ][0]) + 1)); |
1659 | } |
1660 | else if (D_NUMLINES (b, mapping[FILE2])(((b)->ranges[mapping[2]][1]) - ((b)->ranges[mapping[2] ][0]) + 1) == 0) |
1661 | /* Write out a delete */ |
1662 | { |
1663 | if (D_NUMLINES (b, mapping[FILE0])(((b)->ranges[mapping[0]][1]) - ((b)->ranges[mapping[0] ][0]) + 1) == 1) |
1664 | printf_output ("%dd\n", D_LOWLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][0])); |
1665 | else |
1666 | printf_output ("%d,%dd\n", |
1667 | D_LOWLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][0]), |
1668 | D_HIGHLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][1])); |
1669 | } |
1670 | else |
1671 | /* Write out an add or change */ |
1672 | { |
1673 | switch (D_NUMLINES (b, mapping[FILE0])(((b)->ranges[mapping[0]][1]) - ((b)->ranges[mapping[0] ][0]) + 1)) |
1674 | { |
1675 | case 0: |
1676 | printf_output ("%da\n", D_HIGHLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][1])); |
1677 | break; |
1678 | case 1: |
1679 | printf_output ("%dc\n", D_HIGHLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][1])); |
1680 | break; |
1681 | default: |
1682 | printf_output ("%d,%dc\n", |
1683 | D_LOWLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][0]), |
1684 | D_HIGHLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][1])); |
1685 | break; |
1686 | } |
1687 | |
1688 | undotlines (dotlines (b, mapping[FILE22]), |
1689 | D_LOWLINE (b, mapping[FILE0])((b)->ranges[mapping[0]][0]), |
1690 | D_NUMLINES (b, mapping[FILE2])(((b)->ranges[mapping[2]][1]) - ((b)->ranges[mapping[2] ][0]) + 1)); |
1691 | } |
1692 | } |
1693 | if (finalwrite) printf_output ("w\nq\n"); |
1694 | return conflicts_found; |
1695 | } |
1696 | |
1697 | /* |
1698 | * Read from INFILE and output to the standard output file a set of |
1699 | * diff3_ blocks DIFF as a merged file. This acts like 'ed file0 |
1700 | * <[output_diff3_edscript]', except that it works even for binary |
1701 | * data or incomplete lines. |
1702 | * |
1703 | * As before, MAPPING maps from arg list file number to diff file number, |
1704 | * REV_MAPPING is its inverse, |
1705 | * and FILE0, FILE1, and FILE2 are the names of the files. |
1706 | * |
1707 | * Returns 1 if conflicts were found. |
1708 | */ |
1709 | |
1710 | static int |
1711 | output_diff3_merge (infile, diff, mapping, rev_mapping, |
1712 | file0, file1, file2) |
1713 | FILE *infile; |
1714 | struct diff3_block *diff; |
1715 | int const mapping[3], rev_mapping[3]; |
1716 | char const *file0, *file1, *file2; |
1717 | { |
1718 | int c, i; |
1719 | char cc; |
1720 | int conflicts_found = 0, conflict; |
1721 | struct diff3_block *b; |
1722 | int linesread = 0; |
1723 | |
1724 | for (b = diff; b; b = b->next) |
1725 | { |
1726 | /* Must do mapping correctly. */ |
1727 | enum diff_type type |
1728 | = ((b->correspond == DIFF_ALL) ? |
1729 | DIFF_ALL : |
1730 | ((enum diff_type) |
1731 | (((int) DIFF_1ST) |
1732 | + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); |
1733 | char const *format_2nd = "<<<<<<< %s\n"; |
1734 | |
1735 | /* If we aren't supposed to do this output block, skip it. */ |
1736 | switch (type) |
1737 | { |
1738 | default: continue; |
1739 | case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break; |
1740 | case DIFF_3RD: if (overlap_only) continue; conflict = 0; break; |
1741 | case DIFF_ALL: if (simple_only) continue; conflict = flagging; |
1742 | format_2nd = "||||||| %s\n"; |
1743 | break; |
1744 | } |
1745 | |
1746 | /* Copy I lines from file 0. */ |
1747 | i = D_LOWLINE (b, FILE0)((b)->ranges[0][0]) - linesread - 1; |
1748 | linesread += i; |
1749 | while (0 <= --i) |
1750 | do |
1751 | { |
1752 | c = getc (infile)(!__isthreaded ? (--(infile)->_r < 0 ? __srget(infile) : (int)(*(infile)->_p++)) : (getc)(infile)); |
1753 | if (c == EOF(-1)) { |
1754 | if (ferror (infile)(!__isthreaded ? (((infile)->_flags & 0x0040) != 0) : ( ferror)(infile))) |
1755 | diff3_perror_with_exit ("input file"); |
1756 | else if (feof (infile)(!__isthreaded ? (((infile)->_flags & 0x0020) != 0) : ( feof)(infile))) |
1757 | diff3_fatal ("input file shrank"); |
1758 | } |
1759 | cc = c; |
1760 | write_output (&cc, 1); |
1761 | } |
1762 | while (c != '\n'); |
1763 | |
1764 | if (conflict) |
1765 | { |
1766 | conflicts_found = 1; |
1767 | |
1768 | if (type == DIFF_ALL) |
1769 | { |
1770 | /* Put in lines from FILE0 with bracket. */ |
1771 | printf_output ("<<<<<<< %s\n", file0); |
1772 | for (i = 0; |
1773 | i < D_NUMLINES (b, mapping[FILE0])(((b)->ranges[mapping[0]][1]) - ((b)->ranges[mapping[0] ][0]) + 1); |
1774 | i++) |
1775 | write_output (D_RELNUM (b, mapping[FILE0], i)((b)->lines[mapping[0]][i]), |
1776 | D_RELLEN (b, mapping[FILE0], i)((b)->lengths[mapping[0]][i])); |
1777 | } |
1778 | |
1779 | if (show_2nd) |
1780 | { |
1781 | /* Put in lines from FILE1 with bracket. */ |
1782 | printf_output (format_2nd, file1); |
1783 | for (i = 0; |
1784 | i < D_NUMLINES (b, mapping[FILE1])(((b)->ranges[mapping[1]][1]) - ((b)->ranges[mapping[1] ][0]) + 1); |
1785 | i++) |
1786 | write_output (D_RELNUM (b, mapping[FILE1], i)((b)->lines[mapping[1]][i]), |
1787 | D_RELLEN (b, mapping[FILE1], i)((b)->lengths[mapping[1]][i])); |
1788 | } |
1789 | |
1790 | printf_output ("=======\n"); |
1791 | } |
1792 | |
1793 | /* Put in lines from FILE2. */ |
1794 | for (i = 0; |
1795 | i < D_NUMLINES (b, mapping[FILE2])(((b)->ranges[mapping[2]][1]) - ((b)->ranges[mapping[2] ][0]) + 1); |
1796 | i++) |
1797 | write_output (D_RELNUM (b, mapping[FILE2], i)((b)->lines[mapping[2]][i]), |
1798 | D_RELLEN (b, mapping[FILE2], i)((b)->lengths[mapping[2]][i])); |
1799 | |
1800 | if (conflict) |
1801 | printf_output (">>>>>>> %s\n", file2); |
1802 | |
1803 | /* Skip I lines in file 0. */ |
1804 | i = D_NUMLINES (b, FILE0)(((b)->ranges[0][1]) - ((b)->ranges[0][0]) + 1); |
1805 | linesread += i; |
1806 | while (0 <= --i) |
1807 | while ((c = getc (infile)(!__isthreaded ? (--(infile)->_r < 0 ? __srget(infile) : (int)(*(infile)->_p++)) : (getc)(infile))) != '\n') |
1808 | if (c == EOF(-1)) { |
1809 | if (ferror (infile)(!__isthreaded ? (((infile)->_flags & 0x0040) != 0) : ( ferror)(infile))) |
1810 | diff3_perror_with_exit ("input file"); |
1811 | else if (feof (infile)(!__isthreaded ? (((infile)->_flags & 0x0020) != 0) : ( feof)(infile))) |
1812 | { |
1813 | if (i || b->next) |
1814 | diff3_fatal ("input file shrank"); |
1815 | return conflicts_found; |
1816 | } |
1817 | } |
1818 | } |
1819 | /* Copy rest of common file. */ |
1820 | while ((c = getc (infile)(!__isthreaded ? (--(infile)->_r < 0 ? __srget(infile) : (int)(*(infile)->_p++)) : (getc)(infile))) != EOF(-1) || !(ferror (infile)(!__isthreaded ? (((infile)->_flags & 0x0040) != 0) : ( ferror)(infile)) | feof (infile)(!__isthreaded ? (((infile)->_flags & 0x0020) != 0) : ( feof)(infile)))) |
1821 | { |
1822 | cc = c; |
1823 | write_output (&cc, 1); |
1824 | } |
1825 | return conflicts_found; |
1826 | } |
1827 | |
1828 | /* |
1829 | * Reverse the order of the list of diff3 blocks. |
1830 | */ |
1831 | static struct diff3_block * |
1832 | reverse_diff3_blocklist (diff) |
1833 | struct diff3_block *diff; |
1834 | { |
1835 | register struct diff3_block *tmp, *next, *prev; |
1836 | |
1837 | for (tmp = diff, prev = 0; tmp; tmp = next) |
1838 | { |
1839 | next = tmp->next; |
1840 | tmp->next = prev; |
1841 | prev = tmp; |
1842 | } |
1843 | |
1844 | return prev; |
1845 | } |
1846 | |
1847 | static size_t |
1848 | myread (fd, ptr, size) |
1849 | int fd; |
1850 | char *ptr; |
1851 | size_t size; |
1852 | { |
1853 | size_t result = read (fd, ptr, size); |
1854 | if (result == -1) |
1855 | diff3_perror_with_exit ("read failed"); |
1856 | return result; |
1857 | } |
1858 | |
1859 | static void |
1860 | diff3_fatal (string) |
1861 | char const *string; |
1862 | { |
1863 | diff_error ("%s", string, 0); |
1864 | DIFF3_ABORT (2)longjmp(diff3_abort_buf, 2); |
1865 | } |
1866 | |
1867 | static void |
1868 | diff3_perror_with_exit (string) |
1869 | char const *string; |
1870 | { |
1871 | perror_with_name (string); |
1872 | DIFF3_ABORT (2)longjmp(diff3_abort_buf, 2); |
1873 | } |
1874 | |
1875 | static void |
1876 | initialize_main (argcp, argvp) |
1877 | int *argcp; |
1878 | char ***argvp; |
1879 | { |
1880 | always_text = 0; |
1881 | edscript = 0; |
1882 | flagging = 0; |
1883 | tab_align_flag = 0; |
1884 | simple_only = 0; |
1885 | overlap_only = 0; |
1886 | show_2nd = 0; |
1887 | finalwrite = 0; |
1888 | merge = 0; |
1889 | diff_program_name = (*argvp)[0]; |
1890 | outfile = NULL((void *)0); |
1891 | } |
1892 | |
1893 | static void |
1894 | free_diff_blocks(p) |
1895 | struct diff_block *p; |
1896 | { |
1897 | register struct diff_block *next; |
1898 | |
1899 | while (p) |
1900 | { |
1901 | next = p->next; |
1902 | if (p->lines[0]) free(p->lines[0]); |
1903 | if (p->lines[1]) free(p->lines[1]); |
1904 | if (p->lengths[0]) free(p->lengths[0]); |
1905 | if (p->lengths[1]) free(p->lengths[1]); |
1906 | free(p); |
1907 | p = next; |
1908 | } |
1909 | } |
1910 | |
1911 | static void |
1912 | free_diff3_blocks(p) |
1913 | struct diff3_block *p; |
1914 | { |
1915 | register struct diff3_block *next; |
1916 | |
1917 | while (p) |
1918 | { |
1919 | next = p->next; |
1920 | if (p->lines[0]) free(p->lines[0]); |
1921 | if (p->lines[1]) free(p->lines[1]); |
1922 | if (p->lines[2]) free(p->lines[2]); |
1923 | if (p->lengths[0]) free(p->lengths[0]); |
1924 | if (p->lengths[1]) free(p->lengths[1]); |
1925 | if (p->lengths[2]) free(p->lengths[2]); |
1926 | free(p); |
1927 | p = next; |
1928 | } |
1929 | } |