Bug Summary

File:src/gnu/usr.bin/cvs/diff/diff3.c
Warning:line 775, column 8
Value stored to 'high_water_diff' is never read

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))
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
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])
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 */
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++)
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 */
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;
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 */
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 < 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
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++; };
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
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}