Bug Summary

File:src/gnu/usr.bin/cvs/diff/diff3.c
Warning:line 966, column 30
Dereference of null pointer (loaded from variable 'f')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name diff3.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/cvs/obj/diff -resource-dir /usr/local/lib/clang/13.0.0 -D HAVE_CONFIG_H -I . -I /usr/src/gnu/usr.bin/cvs/diff -I .. -I ../src -I /usr/src/gnu/usr.bin/cvs/lib -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/gnu/usr.bin/cvs/obj/diff -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/gnu/usr.bin/cvs/diff/diff3.c
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
30extern char const diff_version_string[];
31
32extern FILE *outfile;
33
34extern const struct diff_callbacks *callbacks;
35
36void write_output PARAMS((char const *, size_t))(char const *, size_t);
37void 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 ;
42void flush_output PARAMS((void))(void);
43
44char * 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
73enum 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 */
85struct 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
94struct 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. */
163static int always_text;
164
165/* If nonzero, write out an ed script instead of the standard diff3 format. */
166static 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. */
171static int flagging;
172
173/* Number of lines to keep in identical prefix and suffix. */
174static int const horizon_lines = 10;
175
176/* Use a tab to align output lines (-T). */
177static int tab_align_flag;
178
179/* If nonzero, do not output information for overlapping diffs. */
180static int simple_only;
181
182/* If nonzero, do not output information for non-overlapping diffs. */
183static int overlap_only;
184
185/* If nonzero, show information for DIFF_2ND diffs. */
186static int show_2nd;
187
188/* If nonzero, include `:wq' at the end of the script
189 to write out the file being edited. */
190static int finalwrite;
191
192/* If nonzero, output a merged file. */
193static int merge;
194
195extern char *diff_program_name;
196
197static char *read_diff PARAMS((char const *, char const *, char **))(char const *, char const *, char **);
198static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int))(char *, char **, size_t *, char *, int);
199static enum diff_type process_diff_control PARAMS((char **, struct diff_block *))(char **, struct diff_block *);
200static 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)
;
201static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int))(char * const[], size_t const[], char *[], size_t[], int);
202static int dotlines PARAMS((struct diff3_block *, int))(struct diff3_block *, int);
203static 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 *)
;
204static 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 *)
;
205static size_t myread PARAMS((int, char *, size_t))(int, char *, size_t);
206static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int))(int, int, int, int, int, int);
207static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *))(struct diff_block *, struct diff_block *);
208static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *))(struct diff3_block *);
209static 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 *)
;
210static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **, char **))(char const *, char const *, struct diff_block **, char **);
211static void check_output PARAMS((FILE *))(FILE *);
212static void diff3_fatal PARAMS((char const *))(char const *);
213static void output_diff3 PARAMS((struct diff3_block *, int const[3], int const[3]))(struct diff3_block *, int const[3], int const[3]);
214static void diff3_perror_with_exit PARAMS((char const *))(char const *);
215static int try_help PARAMS((char const *))(char const *);
216static void undotlines PARAMS((int, int, int))(int, int, int);
217static void usage PARAMS((void))(void);
218static void initialize_main PARAMS((int *, char ***))(int *, char ***);
219static void free_diff_blocks PARAMS((struct diff_block *))(struct diff_block *);
220static void free_diff3_blocks PARAMS((struct diff3_block *))(struct diff3_block *);
221
222/* Functions provided in libdiff.a or other external sources. */
223VOIDvoid *xmalloc PARAMS((size_t))(size_t);
224VOIDvoid *xrealloc PARAMS((VOID *, size_t))(void *, size_t);
225void perror_with_name PARAMS((char const *))(char const *);
226void diff_error PARAMS((char const *, char const *, char const *))(char const *, char const *, char const *);
227
228/* Permit non-local exits from diff3. */
229static jmp_buf diff3_abort_buf;
230#define DIFF3_ABORT(retval)longjmp(diff3_abort_buf, retval) longjmp(diff3_abort_buf, retval)
231
232static 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 */
252int
253diff3_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))
1
Assuming the condition is false
2
Loop condition is false. Execution continues on line 348
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
2.1
'incompat' is <= 1
> 1 /* Ensure at most one of -AeExX3. */
353 || finalwrite & merge /* -i -m would rewrite input file. */
3
Assuming the condition is false
354 || (tag_count
3.1
'tag_count' is 0
&& ! flagging)) /* -L requires one of -AEX. */
355 return try_help ("incompatible options");
356
357 if (argc - optind != 3)
4
Assuming the condition is false
5
Taking false branch
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++)
6
Loop condition is true. Entering loop body
7
Loop condition is true. Entering loop body
8
Loop condition is true. Entering loop body
9
Loop condition is false. Execution continues on line 385
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 )
10
Assuming 'edscript' is 0
11
Assuming 'merge' is 0
12
Taking false branch
387 {
388 common = 1;
389 }
390 else
391 {
392 common = 2;
393 }
394 if (strcmp (file[common], "-") == 0)
13
Assuming the condition is false
14
Taking false branch
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++)
15
Loop condition is true. Entering loop body
16
Loop condition is true. Entering loop body
17
Loop condition is true. Entering loop body
18
Loop condition is false. Execution continues on line 415
413 rev_mapping[mapping[i]] = i;
414
415 for (i = 0; i < 3; i++)
19
Loop condition is true. Entering loop body
21
Loop condition is true. Entering loop body
23
Loop condition is true. Entering loop body
25
Loop condition is false. Execution continues on line 430
416 if (strcmp (file[i], "-") != 0)
20
Taking false branch
22
Taking false branch
24
Taking false branch
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)
26
Assuming 'callbacks' is null
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))
27
Assuming 'out' is not equal to NULL
28
Taking false branch
441 outfile = stdout(&__sF[1]);
442 else
443 {
444 outfile = fopen (out, "w");
445 if (outfile == NULL((void *)0))
29
Assuming 'outfile' is not equal to NULL
30
Taking false branch
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)
31
Assuming 'status' is equal to 0
32
Taking false branch
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,
33
Calling 'process_diff'
76
Returning from 'process_diff'
476 &content0);
477 diff3 = make_3way_diff (thread0, thread1);
77
Calling 'make_3way_diff'
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
514static int
515try_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
524static void
525check_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 */
535static void
536usage ()
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 */
643static struct diff3_block *
644make_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])
78
Taking false branch
717 base_water_thread = 1;
718 else if (!current[1])
79
Taking true branch
719 base_water_thread = 0;
720 else
721 base_water_thread =
722 (D_LOWLINE (current[0], FC)((current[0])->ranges[1][0]) > D_LOWLINE (current[1], FC)((current[1])->ranges[1][0]));
723
724 high_water_thread = base_water_thread;
725
726 high_water_diff = current[high_water_thread];
727
728#if 0
729 /* low and high waters start off same diff */
730 base_water_mark = D_LOWLINE (high_water_diff, FC)((high_water_diff)->ranges[1][0]);
731#endif
732
733 high_water_mark = D_HIGHLINE (high_water_diff, FC)((high_water_diff)->ranges[1][1]);
734
735 /* Make the diff you just got info from into the using class */
736 using[high_water_thread]
737 = last_using[high_water_thread]
738 = high_water_diff;
739 current[high_water_thread] = high_water_diff->next;
740 last_using[high_water_thread]->next = 0;
741
742 /* And mark the other diff */
743 other_thread = high_water_thread ^ 0x1;
744 other_diff = current[other_thread];
745
746 /* Shuffle up the ladder, checking the other diff to see if it
747 needs to be incorporated. */
748 while (other_diff
79.1
'other_diff' is null
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; 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,
80
Calling 'using_to_diff3_block'
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 */ 826static struct diff3_block * 827using_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++)
81
Loop condition is true. Entering loop body
83
Loop condition is true. Entering loop body
85
Loop condition is false. Execution continues on line 860
848 if (using[d])
82
Taking true branch
84
Taking false branch
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++)
86
Loop condition is true. Entering loop body
866 for (ptr = using[d]; ptr; ptr = D_NEXT (ptr)((ptr)->next))
87
Loop condition is true. Entering loop body
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]),
88
Passing null pointer value via 1st parameter 'fromptrs'
89
Calling 'copy_stringlist'
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 */ 950static int 951copy_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;
90
'f' initialized to a null pointer value
959 register char **t = toptrs; 960 register size_t const *fl = fromlengths; 961 register size_t *tl = tolengths; 962 963 while (copynum--)
91
Loop condition is true. Entering loop body
964 { 965 if (*t)
92
Assuming the condition is true
93
Taking true branch
966 { if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; }
94
Assuming the condition is false
95
Dereference of null pointer (loaded from variable 'f')
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 */ 980static struct diff3_block * 981create_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 */ 1049static int 1050compare_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 1073extern char **environ; 1074 1075static struct diff_block * 1076process_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
33.1
'scan_diff' is < 'diff_limit'
73.1
'scan_diff' is >= 'diff_limit'
< diff_limit)
34
Loop condition is true. Entering loop body
74
Loop condition is false. Execution continues on line 1171
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;
35
Storing null pointer value
1096 bptr->lengths[0] = bptr->lengths[1] = 0; 1097 1098 dt = process_diff_control (&scan_diff, bptr);
36
Calling 'process_diff_control'
64
Returning from 'process_diff_control'
1099 if (dt
64.1
'dt' is not equal to ERROR
== ERROR || *scan_diff != '\n')
65
Assuming the condition is false
66
Taking false branch
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)
67
Control jumps to 'case DELETE:' at line 1118
1114 { 1115 case ADD: 1116 bptr->ranges[0][0]++; 1117 break; 1118 case DELETE: 1119 bptr->ranges[1][0]++; 1120 break;
68
Execution continues on line 1130
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
68.1
'dt' is not equal to ADD
!= ADD)
69
Taking true branch
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++)
70
Loop condition is true. Entering loop body
71
Loop condition is false. Execution continues on line 1144
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
71.1
'dt' is not equal to CHANGE
== CHANGE)
72
Taking false branch
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
72.1
'dt' is equal to DELETE
!= DELETE)
73
Taking false branch
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;
75
Returning pointer (loaded from 'block_list'), which participates in a condition later
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 1192static enum diff_type 1193process_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++; };
37
Assuming the condition is false
38
Assuming the condition is false
39
Loop condition is false. Execution continues on line 1216
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; }
;
40
Assuming the condition is true
41
Taking false branch
42
Assuming the condition is false
43
Loop condition is false. Exiting loop
1217 1218 /* Was that the only digit? */ 1219 SKIPWHITE (s){ while (*s == ' ' || *s == '\t') s++; };
44
Assuming the condition is false
45
Assuming the condition is false
46
Loop condition is false. Execution continues on line 1220
1220 if (*s == ',')
47
Assuming the condition is false
48
Taking false branch
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++; };
49
Loop condition is false. Execution continues on line 1231
1231 switch (*s)
50
Control jumps to 'case 100:' at line 1239
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;
51
Execution continues on line 1245
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++; };
52
Assuming the condition is false
53
Assuming the condition is false
54
Loop condition is false. Execution continues on line 1249
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; }
;
55
Assuming the condition is true
56
Taking false branch
57
Assuming the condition is false
58
Loop condition is false. Exiting loop
1250 1251 /* Was that the only digit? */ 1252 SKIPWHITE (s){ while (*s == ' ' || *s == '\t') s++; };
59
Assuming the condition is false
60
Assuming the condition is false
61
Loop condition is false. Execution continues on line 1253
1253 if (*s == ',')
62
Assuming the condition is false
63
Taking false branch
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 1267static char * 1268read_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 */ 1375static char * 1376scan_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 */ 1435static void 1436output_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 */ 1523static int 1524dotlines (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 */ 1552static void 1553undotlines (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 1587static int 1588output_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 1710static int 1711output_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 */ 1831static struct diff3_block * 1832reverse_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
1847static size_t 1848myread (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
1859static void 1860diff3_fatal (string) 1861 char const *string; 1862{ 1863 diff_error ("%s", string, 0); 1864 DIFF3_ABORT (2)longjmp(diff3_abort_buf, 2); 1865} 1866 1867static void 1868diff3_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 1875static void 1876initialize_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 1893static void 1894free_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 1911static void 1912free_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}