diff3.c revision 1.3 1 1.1 christos /* Three way file comparison program (diff3) for Project GNU.
2 1.1 christos Copyright (C) 1988, 1989, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos This program is free software; you can redistribute it and/or modify
5 1.1 christos it under the terms of the GNU General Public License as published by
6 1.1 christos the Free Software Foundation; either version 2, or (at your option)
7 1.1 christos any later version.
8 1.1 christos
9 1.1 christos This program is distributed in the hope that it will be useful,
10 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
11 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 1.1 christos GNU General Public License for more details.
13 1.1 christos
14 1.1 christos */
15 1.1 christos
16 1.1 christos /* Written by Randy Smith */
18 1.1 christos /* Librarification by Tim Pierce */
19 1.1 christos
20 1.1 christos #include "system.h"
21 1.1 christos #include <stdio.h>
22 1.1 christos #include <setjmp.h>
23 1.1 christos #include "getopt.h"
24 1.1 christos #include "diffrun.h"
25 1.1 christos
26 1.1 christos /* diff3.c has a real initialize_main function. */
27 1.1 christos #ifdef initialize_main
28 1.1 christos #undef initialize_main
29 1.1 christos #endif
30 1.1 christos
31 1.1 christos extern char const diff_version_string[];
32 1.1 christos
33 1.1 christos extern FILE *outfile;
34 1.1 christos
35 1.1 christos extern const struct diff_callbacks *callbacks;
36 1.1 christos
37 1.1 christos void write_output PARAMS((char const *, size_t));
38 1.1 christos void printf_output PARAMS((char const *, ...))
39 1.1 christos #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6)
40 1.1 christos __attribute__ ((__format__ (__printf__, 1, 2)))
41 1.1 christos #endif
42 1.1 christos ;
43 1.1 christos void flush_output PARAMS((void));
44 1.1 christos
45 1.1 christos char * cvs_temp_name PARAMS((void));
46 1.1 christos
47 1.1 christos /*
48 1.1 christos * Internal data structures and macros for the diff3 program; includes
49 1.1 christos * data structures for both diff3 diffs and normal diffs.
50 1.1 christos */
51 1.1 christos
52 1.1 christos /* Different files within a three way diff. */
53 1.1 christos #define FILE0 0
54 1.1 christos #define FILE1 1
55 1.1 christos #define FILE2 2
56 1.1 christos
57 1.1 christos /*
58 1.1 christos * A three way diff is built from two two-way diffs; the file which
59 1.1 christos * the two two-way diffs share is:
60 1.1 christos */
61 1.1 christos #define FILEC FILE2
62 1.1 christos
63 1.1 christos /*
64 1.1 christos * Different files within a two way diff.
65 1.1 christos * FC is the common file, FO the other file.
66 1.1 christos */
67 1.1 christos #define FO 0
68 1.1 christos #define FC 1
69 1.1 christos
70 1.1 christos /* The ranges are indexed by */
71 1.1 christos #define START 0
72 1.1 christos #define END 1
73 1.1 christos
74 1.1 christos enum diff_type {
75 1.1 christos ERROR, /* Should not be used */
76 1.1 christos ADD, /* Two way diff add */
77 1.1 christos CHANGE, /* Two way diff change */
78 1.1 christos DELETE, /* Two way diff delete */
79 1.1 christos DIFF_ALL, /* All three are different */
80 1.1 christos DIFF_1ST, /* Only the first is different */
81 1.1 christos DIFF_2ND, /* Only the second */
82 1.1 christos DIFF_3RD /* Only the third */
83 1.1 christos };
84 1.1 christos
85 1.1 christos /* Two way diff */
86 1.1 christos struct diff_block {
87 1.1 christos int ranges[2][2]; /* Ranges are inclusive */
88 1.1 christos char **lines[2]; /* The actual lines (may contain nulls) */
89 1.1 christos size_t *lengths[2]; /* Line lengths (including newlines, if any) */
90 1.1 christos struct diff_block *next;
91 1.1 christos };
92 1.1 christos
93 1.1 christos /* Three way diff */
94 1.1 christos
95 1.1 christos struct diff3_block {
96 1.1 christos enum diff_type correspond; /* Type of diff */
97 1.1 christos int ranges[3][2]; /* Ranges are inclusive */
98 1.1 christos char **lines[3]; /* The actual lines (may contain nulls) */
99 1.1 christos size_t *lengths[3]; /* Line lengths (including newlines, if any) */
100 1.1 christos struct diff3_block *next;
101 1.1 christos };
102 1.1 christos
103 1.1 christos /*
104 1.1 christos * Access the ranges on a diff block.
105 1.1 christos */
106 1.1 christos #define D_LOWLINE(diff, filenum) \
107 1.1 christos ((diff)->ranges[filenum][START])
108 1.1 christos #define D_HIGHLINE(diff, filenum) \
109 1.1 christos ((diff)->ranges[filenum][END])
110 1.1 christos #define D_NUMLINES(diff, filenum) \
111 1.1 christos (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1)
112 1.1 christos
113 1.1 christos /*
114 1.1 christos * Access the line numbers in a file in a diff by relative line
115 1.1 christos * numbers (i.e. line number within the diff itself). Note that these
116 1.1 christos * are lvalues and can be used for assignment.
117 1.1 christos */
118 1.1 christos #define D_RELNUM(diff, filenum, linenum) \
119 1.1 christos ((diff)->lines[filenum][linenum])
120 1.1 christos #define D_RELLEN(diff, filenum, linenum) \
121 1.1 christos ((diff)->lengths[filenum][linenum])
122 1.1 christos
123 1.1 christos /*
124 1.1 christos * And get at them directly, when that should be necessary.
125 1.1 christos */
126 1.1 christos #define D_LINEARRAY(diff, filenum) \
127 1.1 christos ((diff)->lines[filenum])
128 1.1 christos #define D_LENARRAY(diff, filenum) \
129 1.1 christos ((diff)->lengths[filenum])
130 1.1 christos
131 1.1 christos /*
132 1.1 christos * Next block.
133 1.1 christos */
134 1.1 christos #define D_NEXT(diff) ((diff)->next)
135 1.1 christos
136 1.1 christos /*
137 1.1 christos * Access the type of a diff3 block.
138 1.1 christos */
139 1.1 christos #define D3_TYPE(diff) ((diff)->correspond)
140 1.1 christos
141 1.1 christos /*
142 1.1 christos * Line mappings based on diffs. The first maps off the top of the
143 1.1 christos * diff, the second off of the bottom.
144 1.1 christos */
145 1.1 christos #define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \
146 1.1 christos ((lineno) \
147 1.1 christos - D_HIGHLINE ((diff), (fromfile)) \
148 1.1 christos + D_HIGHLINE ((diff), (tofile)))
149 1.1 christos
150 1.1 christos #define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \
151 1.1 christos ((lineno) \
152 1.1 christos - D_LOWLINE ((diff), (fromfile)) \
153 1.1 christos + D_LOWLINE ((diff), (tofile)))
154 1.1 christos
155 1.1 christos /*
156 1.1 christos * General memory allocation function.
157 1.1 christos */
158 1.1 christos #define ALLOCATE(number, type) \
159 1.1 christos (type *) xmalloc ((number) * sizeof (type))
160 1.1 christos
161 1.1 christos /* Options variables for flags set on command line. */
163 1.1 christos
164 1.1 christos /* If nonzero, treat all files as text files, never as binary. */
165 1.1 christos static int always_text;
166 1.1 christos
167 1.1 christos /* If nonzero, write out an ed script instead of the standard diff3 format. */
168 1.1 christos static int edscript;
169 1.1 christos
170 1.1 christos /* If nonzero, in the case of overlapping diffs (type DIFF_ALL),
171 1.1 christos preserve the lines which would normally be deleted from
172 1.1 christos file 1 with a special flagging mechanism. */
173 1.1 christos static int flagging;
174 1.1 christos
175 1.1 christos /* Number of lines to keep in identical prefix and suffix. */
176 1.1 christos static int const horizon_lines = 10;
177 1.1 christos
178 1.1 christos /* Use a tab to align output lines (-T). */
179 1.1 christos static int tab_align_flag;
180 1.1 christos
181 1.1 christos /* If nonzero, do not output information for overlapping diffs. */
182 1.1 christos static int simple_only;
183 1.1 christos
184 1.1 christos /* If nonzero, do not output information for non-overlapping diffs. */
185 1.1 christos static int overlap_only;
186 1.1 christos
187 1.1 christos /* If nonzero, show information for DIFF_2ND diffs. */
188 1.1 christos static int show_2nd;
189 1.1 christos
190 1.1 christos /* If nonzero, include `:wq' at the end of the script
191 1.1 christos to write out the file being edited. */
192 1.1 christos static int finalwrite;
193 1.1 christos
194 1.1 christos /* If nonzero, output a merged file. */
195 1.1 christos static int merge;
196 1.1 christos
197 1.1 christos extern char *diff_program_name;
198 1.1 christos
199 1.1 christos static char *read_diff PARAMS((char const *, char const *, char **));
200 1.1 christos static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int));
201 1.1 christos static enum diff_type process_diff_control PARAMS((char **, struct diff_block *));
202 1.1 christos static int compare_line_list PARAMS((char * const[], size_t const[], char * const[], size_t const[], int));
203 1.1 christos static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int));
204 1.1 christos static int dotlines PARAMS((struct diff3_block *, int));
205 1.1 christos static int output_diff3_edscript PARAMS((struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));
206 1.1 christos static int output_diff3_merge PARAMS((FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));
207 1.1 christos static size_t myread PARAMS((int, char *, size_t));
208 1.1 christos static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int));
209 1.1 christos static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *));
210 1.1 christos static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *));
211 1.1 christos static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *));
212 1.1 christos static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **, char **));
213 1.1 christos static void check_output PARAMS((FILE *));
214 1.1 christos static void diff3_fatal PARAMS((char const *));
215 1.1 christos static void output_diff3 PARAMS((struct diff3_block *, int const[3], int const[3]));
216 1.1 christos static void diff3_perror_with_exit PARAMS((char const *));
217 1.1 christos static int try_help PARAMS((char const *));
218 1.1 christos static void undotlines PARAMS((int, int, int));
219 1.1 christos static void usage PARAMS((void));
220 1.1 christos static void initialize_main PARAMS((int *, char ***));
221 1.1 christos static void free_diff_blocks PARAMS((struct diff_block *));
222 1.1 christos static void free_diff3_blocks PARAMS((struct diff3_block *));
223 1.1 christos
224 1.1 christos /* Functions provided in libdiff.a or other external sources. */
225 1.1 christos VOID *xmalloc PARAMS((size_t));
226 1.1 christos VOID *xrealloc PARAMS((VOID *, size_t));
227 1.1 christos void perror_with_name PARAMS((char const *));
228 1.1 christos void diff_error PARAMS((char const *, char const *, char const *));
229 1.1 christos
230 1.1 christos /* Permit non-local exits from diff3. */
231 1.1 christos static jmp_buf diff3_abort_buf;
232 1.1 christos #define DIFF3_ABORT(retval) longjmp(diff3_abort_buf, retval)
233 1.1 christos
234 1.1 christos static struct option const longopts[] =
235 1.1 christos {
236 1.1 christos {"text", 0, 0, 'a'},
237 1.1 christos {"show-all", 0, 0, 'A'},
238 1.1 christos {"ed", 0, 0, 'e'},
239 1.1 christos {"show-overlap", 0, 0, 'E'},
240 1.1 christos {"label", 1, 0, 'L'},
241 1.1 christos {"merge", 0, 0, 'm'},
242 1.1 christos {"initial-tab", 0, 0, 'T'},
243 1.1 christos {"overlap-only", 0, 0, 'x'},
244 1.1 christos {"easy-only", 0, 0, '3'},
245 1.1 christos {"version", 0, 0, 'v'},
246 1.1 christos {"help", 0, 0, 129},
247 1.1 christos {0, 0, 0, 0}
248 1.1 christos };
249 1.1 christos
250 1.1 christos /*
251 1.1 christos * Main program. Calls diff twice on two pairs of input files,
252 1.1 christos * combines the two diffs, and outputs them.
253 1.1 christos */
254 1.1 christos int
255 1.1 christos diff3_run (argc, argv, out, callbacks_arg)
256 1.1 christos int argc;
257 1.1 christos char **argv;
258 1.1 christos char *out;
259 1.1 christos const struct diff_callbacks *callbacks_arg;
260 1.1 christos {
261 1.1 christos int c, i;
262 1.1 christos int mapping[3];
263 1.1 christos int rev_mapping[3];
264 1.1 christos int incompat = 0;
265 1.1 christos int conflicts_found;
266 1.1 christos int status;
267 1.1 christos struct diff_block *thread0, *thread1, *last_block;
268 1.1 christos char *content0, *content1;
269 1.1 christos struct diff3_block *diff3;
270 1.1 christos int tag_count = 0;
271 1.1 christos char *tag_strings[3];
272 1.1 christos char *commonname;
273 1.1 christos char **file;
274 1.1 christos struct stat statb;
275 1.1 christos int optind_old;
276 1.1 christos int opened_file = 0;
277 1.1 christos
278 1.1 christos callbacks = callbacks_arg;
279 1.1 christos
280 1.1 christos initialize_main (&argc, &argv);
281 1.1 christos
282 1.1 christos optind_old = optind;
283 1.1 christos optind = 0;
284 1.1 christos while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF)
285 1.1 christos {
286 1.1 christos switch (c)
287 1.1 christos {
288 1.1 christos case 'a':
289 1.1 christos always_text = 1;
290 1.1 christos break;
291 1.1 christos case 'A':
292 1.1 christos show_2nd = 1;
293 1.1 christos flagging = 1;
294 1.1 christos incompat++;
295 1.1 christos break;
296 1.1 christos case 'x':
297 1.1 christos overlap_only = 1;
298 1.1 christos incompat++;
299 1.1 christos break;
300 1.1 christos case '3':
301 1.1 christos simple_only = 1;
302 1.1 christos incompat++;
303 1.1 christos break;
304 1.1 christos case 'i':
305 1.1 christos finalwrite = 1;
306 1.1 christos break;
307 1.1 christos case 'm':
308 1.1 christos merge = 1;
309 1.1 christos break;
310 1.1 christos case 'X':
311 1.1 christos overlap_only = 1;
312 1.1 christos /* Falls through */
313 1.1 christos case 'E':
314 1.1 christos flagging = 1;
315 1.1 christos /* Falls through */
316 1.1 christos case 'e':
317 1.1 christos incompat++;
318 1.1 christos break;
319 1.1 christos case 'T':
320 1.1 christos tab_align_flag = 1;
321 1.1 christos break;
322 1.1 christos case 'v':
323 1.1 christos if (callbacks && callbacks->write_stdout)
324 1.1 christos {
325 1.1 christos (*callbacks->write_stdout) ("diff3 - GNU diffutils version ");
326 1.1 christos (*callbacks->write_stdout) (diff_version_string);
327 1.1 christos (*callbacks->write_stdout) ("\n");
328 1.1 christos }
329 1.1 christos else
330 1.1 christos printf ("diff3 - GNU diffutils version %s\n", diff_version_string);
331 1.1 christos return 0;
332 1.1 christos case 129:
333 1.1 christos usage ();
334 1.1 christos if (! callbacks || ! callbacks->write_stdout)
335 1.1 christos check_output (stdout);
336 1.1 christos return 0;
337 1.1 christos case 'L':
338 1.1 christos /* Handle up to three -L options. */
339 1.1 christos if (tag_count < 3)
340 1.1 christos {
341 1.1 christos tag_strings[tag_count++] = optarg;
342 1.1 christos break;
343 1.1 christos }
344 1.1 christos return try_help ("Too many labels were given. The limit is 3.");
345 1.1 christos default:
346 1.1 christos return try_help (0);
347 1.1 christos }
348 1.1 christos }
349 1.1 christos
350 1.1 christos edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */
351 1.1 christos show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */
352 1.1 christos flagging |= ~incompat & merge;
353 1.1 christos
354 1.1 christos if (incompat > 1 /* Ensure at most one of -AeExX3. */
355 1.1 christos || finalwrite & merge /* -i -m would rewrite input file. */
356 1.1 christos || (tag_count && ! flagging)) /* -L requires one of -AEX. */
357 1.1 christos return try_help ("incompatible options");
358 1.1 christos
359 1.1 christos if (argc - optind != 3)
360 1.1 christos return try_help (argc - optind < 3 ? "missing operand" : "extra operand");
361 1.1 christos
362 1.1 christos file = &argv[optind];
363 1.1 christos
364 1.1 christos optind = optind_old;
365 1.1 christos
366 1.1 christos for (i = tag_count; i < 3; i++)
367 1.1 christos tag_strings[i] = file[i];
368 1.1 christos
369 1.1 christos /* Always compare file1 to file2, even if file2 is "-".
370 1.1 christos This is needed for -mAeExX3. Using the file0 as
371 1.1 christos the common file would produce wrong results, because if the
372 1.1 christos file0-file1 diffs didn't line up with the file0-file2 diffs
373 1.1 christos (which is entirely possible since we don't use diff's -n option),
374 1.1 christos diff3 might report phantom changes from file1 to file2. */
375 1.1 christos /* Also try to compare file0 to file1 because this is the where
376 1.1 christos changes are expected to come from. Diffing between these pairs
377 1.1 christos of files is is most likely to return the intended changes. There
378 1.1 christos can also be the same problem with phantom changes from file0 to
379 1.1 christos file1. */
380 1.1 christos /* Historically, the default common file was file2. Ediff for emacs
381 1.1 christos and possibly other applications, have therefore made file2 the
382 1.1 christos ancestor. So, for compatibility, if this is simply a three
383 1.1 christos way diff (not a merge or edscript) then use the old way with
384 1.1 christos file2 as the common file. */
385 1.1 christos
386 1.1 christos {
387 1.1 christos int common;
388 1.1 christos if (edscript || merge )
389 1.1 christos {
390 1.1 christos common = 1;
391 1.1 christos }
392 1.1 christos else
393 1.1 christos {
394 1.1 christos common = 2;
395 1.1 christos }
396 1.1 christos if (strcmp (file[common], "-") == 0)
397 1.1 christos {
398 1.1 christos /* Sigh. We've got standard input as the arg corresponding to
399 1.1 christos the desired common file. We can't call diff twice on
400 1.1 christos stdin. Use another arg as the common file instead. */
401 1.1 christos common = 3 - common;
402 1.1 christos if (strcmp (file[0], "-") == 0 || strcmp (file[common], "-") == 0)
403 1.1 christos {
404 1.1 christos diff_error ("%s", "`-' specified for more than one input file", 0);
405 1.1 christos return 2;
406 1.1 christos }
407 1.1 christos }
408 1.1 christos
409 1.1 christos mapping[0] = 0;
410 1.1 christos mapping[1] = 3 - common;
411 1.1 christos mapping[2] = common;
412 1.1 christos }
413 1.1 christos
414 1.1 christos for (i = 0; i < 3; i++)
415 1.1 christos rev_mapping[mapping[i]] = i;
416 1.1 christos
417 1.1 christos for (i = 0; i < 3; i++)
418 1.1 christos if (strcmp (file[i], "-") != 0)
419 1.1 christos {
420 1.1 christos if (stat (file[i], &statb) < 0)
421 1.1 christos {
422 1.1 christos perror_with_name (file[i]);
423 1.1 christos return 2;
424 1.1 christos }
425 1.1 christos else if (S_ISDIR(statb.st_mode))
426 1.1 christos {
427 1.1 christos diff_error ("%s: Is a directory", file[i], 0);
428 1.1 christos return 2;
429 1.1 christos }
430 1.1 christos }
431 1.1 christos
432 1.1 christos if (callbacks && callbacks->write_output)
433 1.1 christos {
434 1.1 christos if (out != NULL)
435 1.1 christos {
436 1.1 christos diff_error ("write callback with output file", 0, 0);
437 1.1 christos return 2;
438 1.1 christos }
439 1.1 christos }
440 1.1 christos else
441 1.1 christos {
442 1.1 christos if (out == NULL)
443 1.1 christos outfile = stdout;
444 1.1 christos else
445 1.1 christos {
446 1.1 christos outfile = fopen (out, "w");
447 1.1 christos if (outfile == NULL)
448 1.1 christos {
449 1.1 christos perror_with_name (out);
450 1.1 christos return 2;
451 1.1 christos }
452 1.1 christos opened_file = 1;
453 1.1 christos }
454 1.1 christos }
455 1.1 christos
456 1.1 christos /* Set the jump buffer, so that diff may abort execution without
457 1.1 christos terminating the process. */
458 1.1 christos status = setjmp (diff3_abort_buf);
459 1.1 christos if (status != 0)
460 1.1 christos return status;
461 1.1 christos
462 1.1 christos commonname = file[rev_mapping[FILEC]];
463 1.1 christos thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block,
464 1.1 christos &content1);
465 1.1 christos /* What is the intention behind determining horizon_lines from first
466 1.1 christos diff? I think it is better to use the same parameters for each
467 1.1 christos diff so that equal differences in each diff will appear the
468 1.1 christos same. */
469 1.1 christos /*
470 1.1 christos if (thread1)
471 1.1 christos for (i = 0; i < 2; i++)
472 1.1 christos {
473 1.1 christos horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i));
474 1.1 christos horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i));
475 1.1 christos }
476 1.1 christos */
477 1.1 christos thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block,
478 1.1 christos &content0);
479 1.1 christos diff3 = make_3way_diff (thread0, thread1);
480 1.1 christos if (edscript)
481 1.1 christos conflicts_found
482 1.1 christos = output_diff3_edscript (diff3, mapping, rev_mapping,
483 1.1 christos tag_strings[0], tag_strings[1], tag_strings[2]);
484 1.1 christos else if (merge)
485 1.1 christos {
486 1.1 christos FILE *mfp = fopen (file[rev_mapping[FILE0]], "r");
487 1.1 christos if (! mfp)
488 1.1 christos diff3_perror_with_exit (file[rev_mapping[FILE0]]);
489 1.1 christos conflicts_found = output_diff3_merge (mfp, diff3, mapping, rev_mapping,
490 1.1 christos tag_strings[0], tag_strings[1], tag_strings[2]);
491 1.1 christos if (ferror (mfp))
492 1.1 christos diff3_fatal ("read error");
493 1.1 christos if (fclose(mfp) != 0)
494 1.1 christos perror_with_name (file[rev_mapping[FILE0]]);
495 1.1 christos }
496 1.1 christos else
497 1.1 christos {
498 1.1 christos output_diff3 (diff3, mapping, rev_mapping);
499 1.1 christos conflicts_found = 0;
500 1.1 christos }
501 1.1 christos
502 1.1 christos free(content0);
503 1.1 christos free(content1);
504 1.1 christos free_diff3_blocks(diff3);
505 1.1 christos
506 1.1 christos if (! callbacks || ! callbacks->write_output)
507 1.1 christos check_output (outfile);
508 1.1 christos
509 1.1 christos if (opened_file)
510 1.1 christos if (fclose (outfile) != 0)
511 1.1 christos perror_with_name ("close error on output file");
512 1.1 christos
513 1.1 christos return conflicts_found;
514 1.1 christos }
515 1.1 christos
516 1.1 christos static int
517 1.1 christos try_help (reason)
518 1.1 christos char const *reason;
519 1.1 christos {
520 1.1 christos if (reason)
521 1.1 christos diff_error ("%s", reason, 0);
522 1.1 christos diff_error ("Try `%s --help' for more information.", diff_program_name, 0);
523 1.1 christos return 2;
524 1.1 christos }
525 1.1 christos
526 1.1 christos static void
527 1.1 christos check_output (stream)
528 1.1 christos FILE *stream;
529 1.1 christos {
530 1.1 christos if (ferror (stream) || fflush (stream) != 0)
531 1.1 christos diff3_fatal ("write error");
532 1.1 christos }
533 1.1 christos
534 1.1 christos /*
535 1.1 christos * Explain, patiently and kindly, how to use this program.
536 1.1 christos */
537 1.1 christos static void
538 1.1 christos usage ()
539 1.1 christos {
540 1.1 christos if (callbacks && callbacks->write_stdout)
541 1.1 christos {
542 1.1 christos (*callbacks->write_stdout) ("Usage: ");
543 1.1 christos (*callbacks->write_stdout) (diff_program_name);
544 1.1 christos (*callbacks->write_stdout) (" [OPTION]... MYFILE OLDFILE YOURFILE\n\n");
545 1.1 christos
546 1.1 christos (*callbacks->write_stdout) ("\
547 1.1 christos -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\
548 1.1 christos -E --show-overlap Output unmerged changes, bracketing conflicts.\n\
549 1.1 christos -A --show-all Output all changes, bracketing conflicts.\n\
550 1.1 christos -x --overlap-only Output overlapping changes.\n\
551 1.1 christos -X Output overlapping changes, bracketing them.\n\
552 1.1 christos -3 --easy-only Output unmerged nonoverlapping changes.\n\n");
553 1.1 christos (*callbacks->write_stdout) ("\
554 1.1 christos -m --merge Output merged file instead of ed script (default -A).\n\
555 1.1 christos -L LABEL --label=LABEL Use LABEL instead of file name.\n\
556 1.1 christos -i Append `w' and `q' commands to ed scripts.\n\
557 1.1 christos -a --text Treat all files as text.\n\
558 1.1 christos -T --initial-tab Make tabs line up by prepending a tab.\n\n");
559 1.1 christos (*callbacks->write_stdout) ("\
560 1.1 christos -v --version Output version info.\n\
561 1.1 christos --help Output this help.\n\n");
562 1.1 christos (*callbacks->write_stdout) ("If a FILE is `-', read standard input.\n");
563 1.1 christos }
564 1.1 christos else
565 1.1 christos {
566 1.1 christos printf ("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n\n", diff_program_name);
567 1.1 christos
568 1.1 christos printf ("%s", "\
569 1.1 christos -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\
570 1.1 christos -E --show-overlap Output unmerged changes, bracketing conflicts.\n\
571 1.1 christos -A --show-all Output all changes, bracketing conflicts.\n\
572 1.1 christos -x --overlap-only Output overlapping changes.\n\
573 1.1 christos -X Output overlapping changes, bracketing them.\n\
574 1.1 christos -3 --easy-only Output unmerged nonoverlapping changes.\n\n");
575 1.1 christos printf ("%s", "\
576 1.1 christos -m --merge Output merged file instead of ed script (default -A).\n\
577 1.1 christos -L LABEL --label=LABEL Use LABEL instead of file name.\n\
578 1.1 christos -i Append `w' and `q' commands to ed scripts.\n\
579 1.1 christos -a --text Treat all files as text.\n\
580 1.1 christos -T --initial-tab Make tabs line up by prepending a tab.\n\n");
581 1.1 christos printf ("%s", "\
582 1.1 christos -v --version Output version info.\n\
583 1.1 christos --help Output this help.\n\n");
584 1.1 christos printf ("If a FILE is `-', read standard input.\n");
585 1.1 christos }
586 1.1 christos }
587 1.1 christos
588 1.1 christos /*
590 1.1 christos * Routines that combine the two diffs together into one. The
591 1.1 christos * algorithm used follows:
592 1.1 christos *
593 1.1 christos * File2 is shared in common between the two diffs.
594 1.1 christos * Diff02 is the diff between 0 and 2.
595 1.1 christos * Diff12 is the diff between 1 and 2.
596 1.1 christos *
597 1.1 christos * 1) Find the range for the first block in File2.
598 1.1 christos * a) Take the lowest of the two ranges (in File2) in the two
599 1.1 christos * current blocks (one from each diff) as being the low
600 1.1 christos * water mark. Assign the upper end of this block as
601 1.1 christos * being the high water mark and move the current block up
602 1.1 christos * one. Mark the block just moved over as to be used.
603 1.1 christos * b) Check the next block in the diff that the high water
604 1.1 christos * mark is *not* from.
605 1.1 christos *
606 1.1 christos * *If* the high water mark is above
607 1.1 christos * the low end of the range in that block,
608 1.1 christos *
609 1.1 christos * mark that block as to be used and move the current
610 1.1 christos * block up. Set the high water mark to the max of
611 1.1 christos * the high end of this block and the current. Repeat b.
612 1.1 christos *
613 1.1 christos * 2) Find the corresponding ranges in File0 (from the blocks
614 1.1 christos * in diff02; line per line outside of diffs) and in File1.
615 1.1 christos * Create a diff3_block, reserving space as indicated by the ranges.
616 1.1 christos *
617 1.1 christos * 3) Copy all of the pointers for file2 in. At least for now,
618 1.1 christos * do memcmp's between corresponding strings in the two diffs.
619 1.1 christos *
620 1.1 christos * 4) Copy all of the pointers for file0 and 1 in. Get what you
621 1.1 christos * need from file2 (when there isn't a diff block, it's
622 1.1 christos * identical to file2 within the range between diff blocks).
623 1.1 christos *
624 1.1 christos * 5) If the diff blocks you used came from only one of the two
625 1.1 christos * strings of diffs, then that file (i.e. the one other than
626 1.1 christos * the common file in that diff) is the odd person out. If you used
627 1.1 christos * diff blocks from both sets, check to see if files 0 and 1 match:
628 1.1 christos *
629 1.1 christos * Same number of lines? If so, do a set of memcmp's (if a
630 1.1 christos * memcmp matches; copy the pointer over; it'll be easier later
631 1.1 christos * if you have to do any compares). If they match, 0 & 1 are
632 1.1 christos * the same. If not, all three different.
633 1.1 christos *
634 1.1 christos * Then you do it again, until you run out of blocks.
635 1.1 christos *
636 1.1 christos */
637 1.1 christos
638 1.1 christos /*
639 1.1 christos * This routine makes a three way diff (chain of diff3_block's) from two
640 1.1 christos * two way diffs (chains of diff_block's). It is assumed that each of
641 1.1 christos * the two diffs passed are onto the same file (i.e. that each of the
642 1.1 christos * diffs were made "to" the same file). The three way diff pointer
643 1.1 christos * returned will have numbering FILE0--the other file in diff02,
644 1.1 christos * FILE1--the other file in diff12, and FILEC--the common file.
645 1.1 christos */
646 1.1 christos static struct diff3_block *
647 1.1 christos make_3way_diff (thread0, thread1)
648 1.1 christos struct diff_block *thread0, *thread1;
649 1.1 christos {
650 1.1 christos /*
651 1.1 christos * This routine works on the two diffs passed to it as threads.
652 1.1 christos * Thread number 0 is diff02, thread number 1 is diff12. The USING
653 1.1 christos * array is set to the base of the list of blocks to be used to
654 1.1 christos * construct each block of the three way diff; if no blocks from a
655 1.1 christos * particular thread are to be used, that element of the using array
656 1.1 christos * is set to 0. The elements LAST_USING array are set to the last
657 1.1 christos * elements on each of the using lists.
658 1.1 christos *
659 1.1 christos * The HIGH_WATER_MARK is set to the highest line number in the common file
660 1.1 christos * described in any of the diffs in either of the USING lists. The
661 1.1 christos * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK
662 1.1 christos * and BASE_WATER_THREAD describe the lowest line number in the common file
663 1.1 christos * described in any of the diffs in either of the USING lists. The
664 1.1 christos * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
665 1.1 christos * taken.
666 1.1 christos *
667 1.1 christos * The HIGH_WATER_DIFF should always be equal to LAST_USING
668 1.1 christos * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for
669 1.1 christos * higher water, and should always be equal to
670 1.1 christos * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread
671 1.1 christos * in which the OTHER_DIFF is, and hence should always be equal to
672 1.1 christos * HIGH_WATER_THREAD ^ 0x1.
673 1.1 christos *
674 1.1 christos * The variable LAST_DIFF is kept set to the last diff block produced
675 1.1 christos * by this routine, for line correspondence purposes between that diff
676 1.1 christos * and the one currently being worked on. It is initialized to
677 1.1 christos * ZERO_DIFF before any blocks have been created.
678 1.1 christos */
679 1.1 christos
680 1.1 christos struct diff_block
681 1.1 christos *using[2],
682 1.1 christos *last_using[2],
683 1.1 christos *current[2];
684 1.1 christos
685 1.1 christos int
686 1.1 christos high_water_mark;
687 1.1 christos
688 1.1 christos int
689 1.1 christos high_water_thread,
690 1.1 christos base_water_thread,
691 1.1 christos other_thread;
692 1.1 christos
693 1.1 christos struct diff_block
694 1.1 christos *high_water_diff,
695 1.1 christos *other_diff;
696 1.1 christos
697 1.1 christos struct diff3_block
698 1.1 christos *result,
699 1.1 christos *tmpblock,
700 1.1 christos **result_end;
701 1.1 christos
702 1.1 christos struct diff3_block const *last_diff3;
703 1.1 christos
704 1.1 christos static struct diff3_block const zero_diff3 = { 0 };
705 1.1 christos
706 1.1 christos /* Initialization */
707 1.1 christos result = 0;
708 1.1 christos result_end = &result;
709 1.1 christos current[0] = thread0; current[1] = thread1;
710 1.1 christos last_diff3 = &zero_diff3;
711 1.1 christos
712 1.1 christos /* Sniff up the threads until we reach the end */
713 1.1 christos
714 1.1 christos while (current[0] || current[1])
715 1.1 christos {
716 1.1 christos using[0] = using[1] = last_using[0] = last_using[1] = 0;
717 1.1 christos
718 1.1 christos /* Setup low and high water threads, diffs, and marks. */
719 1.1 christos if (!current[0])
720 1.1 christos base_water_thread = 1;
721 1.1 christos else if (!current[1])
722 1.1 christos base_water_thread = 0;
723 1.1 christos else
724 1.1 christos base_water_thread =
725 1.1 christos (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC));
726 1.1 christos
727 1.1 christos high_water_thread = base_water_thread;
728 1.1 christos
729 1.1 christos high_water_diff = current[high_water_thread];
730 1.1 christos
731 1.1 christos #if 0
732 1.1 christos /* low and high waters start off same diff */
733 1.1 christos base_water_mark = D_LOWLINE (high_water_diff, FC);
734 1.1 christos #endif
735 1.1 christos
736 1.1 christos high_water_mark = D_HIGHLINE (high_water_diff, FC);
737 1.1 christos
738 1.1 christos /* Make the diff you just got info from into the using class */
739 1.1 christos using[high_water_thread]
740 1.1 christos = last_using[high_water_thread]
741 1.1 christos = high_water_diff;
742 1.1 christos current[high_water_thread] = high_water_diff->next;
743 1.1 christos last_using[high_water_thread]->next = 0;
744 1.1 christos
745 1.1 christos /* And mark the other diff */
746 1.1 christos other_thread = high_water_thread ^ 0x1;
747 1.1 christos other_diff = current[other_thread];
748 1.1 christos
749 1.1 christos /* Shuffle up the ladder, checking the other diff to see if it
750 1.1 christos needs to be incorporated. */
751 1.1 christos while (other_diff
752 1.1 christos && D_LOWLINE (other_diff, FC) <= high_water_mark + 1)
753 1.1 christos {
754 1.1 christos
755 1.1 christos /* Incorporate this diff into the using list. Note that
756 1.1 christos this doesn't take it off the current list */
757 1.1 christos if (using[other_thread])
758 1.1 christos last_using[other_thread]->next = other_diff;
759 1.1 christos else
760 1.1 christos using[other_thread] = other_diff;
761 1.1 christos last_using[other_thread] = other_diff;
762 1.1 christos
763 1.1 christos /* Take it off the current list. Note that this following
764 1.1 christos code assumes that other_diff enters it equal to
765 1.1 christos current[high_water_thread ^ 0x1] */
766 1.1 christos current[other_thread] = current[other_thread]->next;
767 1.1 christos other_diff->next = 0;
768 1.1 christos
769 1.1 christos /* Set the high_water stuff
770 1.1 christos If this comparison is equal, then this is the last pass
771 1.1 christos through this loop; since diff blocks within a given
772 1.1 christos thread cannot overlap, the high_water_mark will be
773 1.1 christos *below* the range_start of either of the next diffs. */
774 1.1 christos
775 1.1 christos if (high_water_mark < D_HIGHLINE (other_diff, FC))
776 1.1 christos {
777 1.1 christos high_water_thread ^= 1;
778 1.1 christos high_water_diff = other_diff;
779 1.1 christos high_water_mark = D_HIGHLINE (other_diff, FC);
780 1.1 christos }
781 1.1 christos
782 1.1 christos /* Set the other diff */
783 1.1 christos other_thread = high_water_thread ^ 0x1;
784 1.1 christos other_diff = current[other_thread];
785 1.1 christos }
786 1.1 christos
787 1.1 christos /* The using lists contain a list of all of the blocks to be
788 1.1 christos included in this diff3_block. Create it. */
789 1.1 christos
790 1.1 christos tmpblock = using_to_diff3_block (using, last_using,
791 1.1 christos base_water_thread, high_water_thread,
792 1.1 christos last_diff3);
793 1.1 christos free_diff_blocks(using[0]);
794 1.1 christos free_diff_blocks(using[1]);
795 1.1 christos
796 1.1 christos if (!tmpblock)
797 1.1 christos diff3_fatal ("internal error: screwup in format of diff blocks");
798 1.1 christos
799 1.1 christos /* Put it on the list. */
800 1.1 christos *result_end = tmpblock;
801 1.1 christos result_end = &tmpblock->next;
802 1.1 christos
803 1.1 christos /* Set up corresponding lines correctly. */
804 1.1 christos last_diff3 = tmpblock;
805 1.1 christos }
806 1.1 christos return result;
807 1.1 christos }
808 1.1 christos
809 1.1 christos /*
810 1.1 christos * using_to_diff3_block:
811 1.1 christos * This routine takes two lists of blocks (from two separate diff
812 1.1 christos * threads) and puts them together into one diff3 block.
813 1.1 christos * It then returns a pointer to this diff3 block or 0 for failure.
814 1.1 christos *
815 1.1 christos * All arguments besides using are for the convenience of the routine;
816 1.1 christos * they could be derived from the using array.
817 1.1 christos * LAST_USING is a pair of pointers to the last blocks in the using
818 1.1 christos * structure.
819 1.1 christos * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
820 1.1 christos * and highest line numbers for File0.
821 1.1 christos * last_diff3 contains the last diff produced in the calling routine.
822 1.1 christos * This is used for lines mappings which would still be identical to
823 1.1 christos * the state that diff ended in.
824 1.1 christos *
825 1.1 christos * A distinction should be made in this routine between the two diffs
826 1.1 christos * that are part of a normal two diff block, and the three diffs that
827 1.1 christos * are part of a diff3_block.
828 1.1 christos */
829 1.1 christos static struct diff3_block *
830 1.1 christos using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3)
831 1.1 christos struct diff_block
832 1.1 christos *using[2],
833 1.1 christos *last_using[2];
834 1.1 christos int low_thread, high_thread;
835 1.1 christos struct diff3_block const *last_diff3;
836 1.1 christos {
837 1.1 christos int low[2], high[2];
838 1.1 christos struct diff3_block *result;
839 1.1 christos struct diff_block *ptr;
840 1.1 christos int d, i;
841 1.1 christos
842 1.1 christos /* Find the range in the common file. */
843 1.1 christos int lowc = D_LOWLINE (using[low_thread], FC);
844 1.1 christos int highc = D_HIGHLINE (last_using[high_thread], FC);
845 1.1 christos
846 1.1 christos /* Find the ranges in the other files.
847 1.1 christos If using[d] is null, that means that the file to which that diff
848 1.1 christos refers is equivalent to the common file over this range. */
849 1.1 christos
850 1.1 christos for (d = 0; d < 2; d++)
851 1.1 christos if (using[d])
852 1.1 christos {
853 1.1 christos low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc);
854 1.1 christos high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc);
855 1.1 christos }
856 1.1 christos else
857 1.1 christos {
858 1.1 christos low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc);
859 1.1 christos high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc);
860 1.1 christos }
861 1.1 christos
862 1.1 christos /* Create a block with the appropriate sizes */
863 1.1 christos result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc);
864 1.1 christos
865 1.1 christos /* Copy information for the common file.
866 1.1 christos Return with a zero if any of the compares failed. */
867 1.1 christos
868 1.1 christos for (d = 0; d < 2; d++)
869 1.1 christos for (ptr = using[d]; ptr; ptr = D_NEXT (ptr))
870 1.1 christos {
871 1.1 christos int result_offset = D_LOWLINE (ptr, FC) - lowc;
872 1.1 christos
873 1.1 christos if (!copy_stringlist (D_LINEARRAY (ptr, FC),
874 1.1 christos D_LENARRAY (ptr, FC),
875 1.1 christos D_LINEARRAY (result, FILEC) + result_offset,
876 1.1 christos D_LENARRAY (result, FILEC) + result_offset,
877 1.1 christos D_NUMLINES (ptr, FC)))
878 1.1 christos return 0;
879 1.1 christos }
880 1.1 christos
881 1.1 christos /* Copy information for file d. First deal with anything that might be
882 1.1 christos before the first diff. */
883 1.1 christos
884 1.1 christos for (d = 0; d < 2; d++)
885 1.1 christos {
886 1.1 christos struct diff_block *u = using[d];
887 1.1 christos int lo = low[d], hi = high[d];
888 1.1 christos
889 1.1 christos for (i = 0;
890 1.1 christos i + lo < (u ? D_LOWLINE (u, FO) : hi + 1);
891 1.1 christos i++)
892 1.1 christos {
893 1.1 christos D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i);
894 1.1 christos D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i);
895 1.1 christos }
896 1.1 christos
897 1.1 christos for (ptr = u; ptr; ptr = D_NEXT (ptr))
898 1.1 christos {
899 1.1 christos int result_offset = D_LOWLINE (ptr, FO) - lo;
900 1.1 christos int linec;
901 1.1 christos
902 1.1 christos if (!copy_stringlist (D_LINEARRAY (ptr, FO),
903 1.1 christos D_LENARRAY (ptr, FO),
904 1.1 christos D_LINEARRAY (result, FILE0 + d) + result_offset,
905 1.1 christos D_LENARRAY (result, FILE0 + d) + result_offset,
906 1.1 christos D_NUMLINES (ptr, FO)))
907 1.1 christos return 0;
908 1.1 christos
909 1.1 christos /* Catch the lines between here and the next diff */
910 1.1 christos linec = D_HIGHLINE (ptr, FC) + 1 - lowc;
911 1.1 christos for (i = D_HIGHLINE (ptr, FO) + 1 - lo;
912 1.1 christos i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo;
913 1.1 christos i++)
914 1.1 christos {
915 1.1 christos D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec);
916 1.1 christos D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec);
917 1.1 christos linec++;
918 1.1 christos }
919 1.1 christos }
920 1.1 christos }
921 1.1 christos
922 1.1 christos /* Set correspond */
923 1.1 christos if (!using[0])
924 1.1 christos D3_TYPE (result) = DIFF_2ND;
925 1.1 christos else if (!using[1])
926 1.1 christos D3_TYPE (result) = DIFF_1ST;
927 1.1 christos else
928 1.1 christos {
929 1.1 christos int nl0 = D_NUMLINES (result, FILE0);
930 1.1 christos int nl1 = D_NUMLINES (result, FILE1);
931 1.1 christos
932 1.1 christos if (nl0 != nl1
933 1.1 christos || !compare_line_list (D_LINEARRAY (result, FILE0),
934 1.1 christos D_LENARRAY (result, FILE0),
935 1.1 christos D_LINEARRAY (result, FILE1),
936 1.1 christos D_LENARRAY (result, FILE1),
937 1.1 christos nl0))
938 1.1 christos D3_TYPE (result) = DIFF_ALL;
939 1.1 christos else
940 1.1 christos D3_TYPE (result) = DIFF_3RD;
941 1.1 christos }
942 1.1 christos
943 1.1 christos return result;
944 1.1 christos }
945 1.1 christos
946 1.1 christos /*
947 1.1 christos * This routine copies pointers from a list of strings to a different list
948 1.1 christos * of strings. If a spot in the second list is already filled, it
949 1.1 christos * makes sure that it is filled with the same string; if not it
950 1.1 christos * returns 0, the copy incomplete.
951 1.1 christos * Upon successful completion of the copy, it returns 1.
952 1.1 christos */
953 1.1 christos static int
954 1.1 christos copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
955 1.1 christos char * const fromptrs[];
956 1.1 christos char *toptrs[];
957 1.1 christos size_t const fromlengths[];
958 1.1 christos size_t tolengths[];
959 1.1 christos int copynum;
960 1.1 christos {
961 1.1 christos register char * const *f = fromptrs;
962 1.1 christos register char **t = toptrs;
963 1.1 christos register size_t const *fl = fromlengths;
964 1.1 christos register size_t *tl = tolengths;
965 1.1 christos
966 1.1 christos while (copynum--)
967 1.1 christos {
968 1.1 christos if (*t)
969 1.1 christos { if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; }
970 1.1 christos else
971 1.1 christos { *t = *f ; *tl = *fl; }
972 1.1 christos
973 1.1 christos t++; f++; tl++; fl++;
974 1.1 christos }
975 1.1 christos return 1;
976 1.1 christos }
977 1.1 christos
978 1.1 christos /*
979 1.1 christos * Create a diff3_block, with ranges as specified in the arguments.
980 1.1 christos * Allocate the arrays for the various pointers (and zero them) based
981 1.1 christos * on the arguments passed. Return the block as a result.
982 1.1 christos */
983 1.1 christos static struct diff3_block *
984 1.1 christos create_diff3_block (low0, high0, low1, high1, low2, high2)
985 1.1 christos register int low0, high0, low1, high1, low2, high2;
986 1.1 christos {
987 1.1 christos struct diff3_block *result = ALLOCATE (1, struct diff3_block);
988 1.1 christos int numlines;
989 1.1 christos
990 1.1 christos D3_TYPE (result) = ERROR;
991 1.1 christos D_NEXT (result) = 0;
992 1.1 christos
993 1.1 christos /* Assign ranges */
994 1.1 christos D_LOWLINE (result, FILE0) = low0;
995 1.1 christos D_HIGHLINE (result, FILE0) = high0;
996 1.1 christos D_LOWLINE (result, FILE1) = low1;
997 1.1 christos D_HIGHLINE (result, FILE1) = high1;
998 1.1 christos D_LOWLINE (result, FILE2) = low2;
999 1.1 christos D_HIGHLINE (result, FILE2) = high2;
1000 1.1 christos
1001 1.1 christos /* Allocate and zero space */
1002 1.1 christos numlines = D_NUMLINES (result, FILE0);
1003 1.1 christos if (numlines)
1004 1.1 christos {
1005 1.1 christos D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *);
1006 1.1 christos D_LENARRAY (result, FILE0) = ALLOCATE (numlines, size_t);
1007 1.1 christos bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)));
1008 1.1 christos bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (size_t)));
1009 1.1 christos }
1010 1.1 christos else
1011 1.1 christos {
1012 1.1 christos D_LINEARRAY (result, FILE0) = 0;
1013 1.1 christos D_LENARRAY (result, FILE0) = 0;
1014 1.1 christos }
1015 1.1 christos
1016 1.1 christos numlines = D_NUMLINES (result, FILE1);
1017 1.1 christos if (numlines)
1018 1.1 christos {
1019 1.1 christos D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *);
1020 1.1 christos D_LENARRAY (result, FILE1) = ALLOCATE (numlines, size_t);
1021 1.1 christos bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)));
1022 1.1 christos bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (size_t)));
1023 1.1 christos }
1024 1.1 christos else
1025 1.1 christos {
1026 1.1 christos D_LINEARRAY (result, FILE1) = 0;
1027 1.1 christos D_LENARRAY (result, FILE1) = 0;
1028 1.1 christos }
1029 1.1 christos
1030 1.1 christos numlines = D_NUMLINES (result, FILE2);
1031 1.1 christos if (numlines)
1032 1.1 christos {
1033 1.1 christos D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *);
1034 1.1 christos D_LENARRAY (result, FILE2) = ALLOCATE (numlines, size_t);
1035 1.1 christos bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)));
1036 1.1 christos bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (size_t)));
1037 1.1 christos }
1038 1.1 christos else
1039 1.1 christos {
1040 1.1 christos D_LINEARRAY (result, FILE2) = 0;
1041 1.1 christos D_LENARRAY (result, FILE2) = 0;
1042 1.1 christos }
1043 1.1 christos
1044 1.1 christos /* Return */
1045 1.1 christos return result;
1046 1.1 christos }
1047 1.1 christos
1048 1.1 christos /*
1049 1.1 christos * Compare two lists of lines of text.
1050 1.1 christos * Return 1 if they are equivalent, 0 if not.
1051 1.1 christos */
1052 1.1 christos static int
1053 1.1 christos compare_line_list (list1, lengths1, list2, lengths2, nl)
1054 1.1 christos char * const list1[], * const list2[];
1055 1.1 christos size_t const lengths1[], lengths2[];
1056 1.1 christos int nl;
1057 1.1 christos {
1058 1.1 christos char
1059 1.1 christos * const *l1 = list1,
1060 1.1 christos * const *l2 = list2;
1061 1.1 christos size_t const
1062 1.1 christos *lgths1 = lengths1,
1063 1.1 christos *lgths2 = lengths2;
1064 1.1 christos
1065 1.1 christos while (nl--)
1066 1.1 christos if (!*l1 || !*l2 || *lgths1 != *lgths2++
1067 1.1 christos || memcmp (*l1++, *l2++, *lgths1++))
1068 1.1 christos return 0;
1069 1.1 christos return 1;
1070 1.1 christos }
1071 1.1 christos
1072 1.1 christos /*
1074 1.1 christos * Routines to input and parse two way diffs.
1075 1.1 christos */
1076 1.1 christos
1077 1.1 christos extern char **environ;
1078 1.1 christos
1079 1.1 christos static struct diff_block *
1080 1.1 christos process_diff (filea, fileb, last_block, diff_contents)
1081 1.1 christos char const *filea, *fileb;
1082 1.1 christos struct diff_block **last_block;
1083 1.1 christos char **diff_contents;
1084 1.1 christos {
1085 1.1 christos char *diff_limit;
1086 1.1 christos char *scan_diff;
1087 1.1 christos enum diff_type dt;
1088 1.1 christos int i;
1089 1.1 christos struct diff_block *block_list, **block_list_end, *bptr;
1090 1.1 christos
1091 1.1 christos diff_limit = read_diff (filea, fileb, diff_contents);
1092 1.1 christos scan_diff = *diff_contents;
1093 1.1 christos block_list_end = &block_list;
1094 1.1 christos bptr = 0; /* Pacify `gcc -W'. */
1095 1.1 christos
1096 1.1 christos while (scan_diff < diff_limit)
1097 1.1 christos {
1098 1.1 christos bptr = ALLOCATE (1, struct diff_block);
1099 1.1 christos bptr->lines[0] = bptr->lines[1] = 0;
1100 1.1 christos bptr->lengths[0] = bptr->lengths[1] = 0;
1101 1.1 christos
1102 1.1 christos dt = process_diff_control (&scan_diff, bptr);
1103 1.1 christos if (dt == ERROR || *scan_diff != '\n')
1104 1.1 christos {
1105 1.1 christos char *serr;
1106 1.1 christos
1107 1.1 christos for (serr = scan_diff; *serr != '\n'; serr++)
1108 1.1 christos ;
1109 1.1 christos *serr = '\0';
1110 1.1 christos diff_error ("diff error: %s", scan_diff, 0);
1111 1.1 christos *serr = '\n';
1112 1.1 christos DIFF3_ABORT (2);
1113 1.1 christos }
1114 1.1 christos scan_diff++;
1115 1.1 christos
1116 1.1 christos /* Force appropriate ranges to be null, if necessary */
1117 1.1 christos switch (dt)
1118 1.1 christos {
1119 1.1 christos case ADD:
1120 1.1 christos bptr->ranges[0][0]++;
1121 1.1 christos break;
1122 1.1 christos case DELETE:
1123 1.1 christos bptr->ranges[1][0]++;
1124 1.1 christos break;
1125 1.1 christos case CHANGE:
1126 1.1 christos break;
1127 1.1 christos default:
1128 1.1 christos diff3_fatal ("internal error: invalid diff type in process_diff");
1129 1.1 christos break;
1130 1.1 christos }
1131 1.1 christos
1132 1.1 christos /* Allocate space for the pointers for the lines from filea, and
1133 1.1 christos parcel them out among these pointers */
1134 1.1 christos if (dt != ADD)
1135 1.1 christos {
1136 1.1 christos int numlines = D_NUMLINES (bptr, 0);
1137 1.1 christos bptr->lines[0] = ALLOCATE (numlines, char *);
1138 1.1 christos bptr->lengths[0] = ALLOCATE (numlines, size_t);
1139 1.1 christos for (i = 0; i < numlines; i++)
1140 1.1 christos scan_diff = scan_diff_line (scan_diff,
1141 1.1 christos &(bptr->lines[0][i]),
1142 1.1 christos &(bptr->lengths[0][i]),
1143 1.1 christos diff_limit,
1144 1.1 christos '<');
1145 1.1 christos }
1146 1.1 christos
1147 1.1 christos /* Get past the separator for changes */
1148 1.1 christos if (dt == CHANGE)
1149 1.1 christos {
1150 1.1 christos if (strncmp (scan_diff, "---\n", 4))
1151 1.1 christos diff3_fatal ("invalid diff format; invalid change separator");
1152 1.1 christos scan_diff += 4;
1153 1.1 christos }
1154 1.1 christos
1155 1.1 christos /* Allocate space for the pointers for the lines from fileb, and
1156 1.1 christos parcel them out among these pointers */
1157 1.1 christos if (dt != DELETE)
1158 1.1 christos {
1159 1.1 christos int numlines = D_NUMLINES (bptr, 1);
1160 1.1 christos bptr->lines[1] = ALLOCATE (numlines, char *);
1161 1.1 christos bptr->lengths[1] = ALLOCATE (numlines, size_t);
1162 1.1 christos for (i = 0; i < numlines; i++)
1163 1.1 christos scan_diff = scan_diff_line (scan_diff,
1164 1.1 christos &(bptr->lines[1][i]),
1165 1.1 christos &(bptr->lengths[1][i]),
1166 1.1 christos diff_limit,
1167 1.1 christos '>');
1168 1.1 christos }
1169 1.1 christos
1170 1.1 christos /* Place this block on the blocklist. */
1171 1.1 christos *block_list_end = bptr;
1172 1.1 christos block_list_end = &bptr->next;
1173 1.1 christos }
1174 1.1 christos
1175 1.1 christos *block_list_end = 0;
1176 1.1 christos *last_block = bptr;
1177 1.1 christos return block_list;
1178 1.1 christos }
1179 1.1 christos
1180 1.1 christos /*
1181 1.1 christos * This routine will parse a normal format diff control string. It
1182 1.1 christos * returns the type of the diff (ERROR if the format is bad). All of
1183 1.1 christos * the other important information is filled into to the structure
1184 1.1 christos * pointed to by db, and the string pointer (whose location is passed
1185 1.1 christos * to this routine) is updated to point beyond the end of the string
1186 1.1 christos * parsed. Note that only the ranges in the diff_block will be set by
1187 1.1 christos * this routine.
1188 1.1 christos *
1189 1.1 christos * If some specific pair of numbers has been reduced to a single
1190 1.1 christos * number, then both corresponding numbers in the diff block are set
1191 1.1 christos * to that number. In general these numbers are interpetted as ranges
1192 1.1 christos * inclusive, unless being used by the ADD or DELETE commands. It is
1193 1.1 christos * assumed that these will be special cased in a superior routine.
1194 1.1 christos */
1195 1.1 christos
1196 1.1 christos static enum diff_type
1197 1.1 christos process_diff_control (string, db)
1198 1.1 christos char **string;
1199 1.1 christos struct diff_block *db;
1200 1.1 christos {
1201 1.1 christos char *s = *string;
1202 1.1 christos int holdnum;
1203 1.1 christos enum diff_type type;
1204 1.1 christos
1205 1.1 christos /* These macros are defined here because they can use variables
1206 1.1 christos defined in this function. Don't try this at home kids, we're
1207 1.1 christos trained professionals!
1208 1.1 christos
1209 1.1 christos Also note that SKIPWHITE only recognizes tabs and spaces, and
1210 1.1 christos that READNUM can only read positive, integral numbers */
1211 1.1 christos
1212 1.1 christos #define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; }
1213 1.1 christos #define READNUM(s, num) \
1214 1.1 christos { unsigned char c = *s; if (!ISDIGIT (c)) return ERROR; holdnum = 0; \
1215 1.1 christos do { holdnum = (c - '0' + holdnum * 10); } \
1216 1.1 christos while (ISDIGIT (c = *++s)); (num) = holdnum; }
1217 1.1 christos
1218 1.1 christos /* Read first set of digits */
1219 1.1 christos SKIPWHITE (s);
1220 1.1 christos READNUM (s, db->ranges[0][START]);
1221 1.1 christos
1222 1.1 christos /* Was that the only digit? */
1223 1.1 christos SKIPWHITE (s);
1224 1.1 christos if (*s == ',')
1225 1.1 christos {
1226 1.1 christos /* Get the next digit */
1227 1.1 christos s++;
1228 1.1 christos READNUM (s, db->ranges[0][END]);
1229 1.1 christos }
1230 1.1 christos else
1231 1.1 christos db->ranges[0][END] = db->ranges[0][START];
1232 1.1 christos
1233 1.1 christos /* Get the letter */
1234 1.1 christos SKIPWHITE (s);
1235 1.1 christos switch (*s)
1236 1.1 christos {
1237 1.1 christos case 'a':
1238 1.1 christos type = ADD;
1239 1.1 christos break;
1240 1.1 christos case 'c':
1241 1.1 christos type = CHANGE;
1242 1.1 christos break;
1243 1.1 christos case 'd':
1244 1.1 christos type = DELETE;
1245 1.1 christos break;
1246 1.1 christos default:
1247 1.1 christos return ERROR; /* Bad format */
1248 1.1 christos }
1249 1.1 christos s++; /* Past letter */
1250 1.1 christos
1251 1.1 christos /* Read second set of digits */
1252 1.1 christos SKIPWHITE (s);
1253 1.1 christos READNUM (s, db->ranges[1][START]);
1254 1.1 christos
1255 1.1 christos /* Was that the only digit? */
1256 1.1 christos SKIPWHITE (s);
1257 1.1 christos if (*s == ',')
1258 1.1 christos {
1259 1.1 christos /* Get the next digit */
1260 1.1 christos s++;
1261 1.1 christos READNUM (s, db->ranges[1][END]);
1262 1.1 christos SKIPWHITE (s); /* To move to end */
1263 1.1 christos }
1264 1.1 christos else
1265 1.1 christos db->ranges[1][END] = db->ranges[1][START];
1266 1.1 christos
1267 1.1 christos *string = s;
1268 1.1 christos return type;
1269 1.1 christos }
1270 1.1 christos
1271 1.1 christos static char *
1272 1.1 christos read_diff (filea, fileb, output_placement)
1273 1.1 christos char const *filea, *fileb;
1274 1.1 christos char **output_placement;
1275 1.1 christos {
1276 1.1 christos char *diff_result;
1277 1.1 christos size_t bytes, current_chunk_size, total;
1278 1.1 christos int fd, wstatus;
1279 1.1 christos struct stat pipestat;
1280 1.1 christos FILE *outfile_hold;
1281 1.1 christos const struct diff_callbacks *callbacks_hold;
1282 1.1 christos struct diff_callbacks my_callbacks;
1283 1.1 christos struct diff_callbacks *my_callbacks_arg;
1284 1.1 christos
1285 1.1 christos /* 302 / 1000 is log10(2.0) rounded up. Subtract 1 for the sign bit;
1286 1.1 christos add 1 for integer division truncation; add 1 more for a minus sign. */
1287 1.1 christos #define INT_STRLEN_BOUND(type) ((sizeof(type)*CHAR_BIT - 1) * 302 / 1000 + 2)
1288 1.1 christos
1289 1.1 christos char const *argv[7];
1290 1.1 christos char horizon_arg[17 + INT_STRLEN_BOUND (int)];
1291 1.1 christos char const **ap;
1292 1.1 christos char *diffout;
1293 1.1 christos
1294 1.1 christos ap = argv;
1295 1.1 christos *ap++ = "diff";
1296 1.1 christos if (always_text)
1297 1.1 christos *ap++ = "-a";
1298 1.1 christos sprintf (horizon_arg, "--horizon-lines=%d", horizon_lines);
1299 1.1 christos *ap++ = horizon_arg;
1300 1.1 christos *ap++ = "--";
1301 1.1 christos *ap++ = filea;
1302 1.1 christos *ap++ = fileb;
1303 1.1 christos *ap = 0;
1304 1.1 christos
1305 1.1 christos diffout = cvs_temp_name ();
1306 1.1 christos
1307 1.1 christos outfile_hold = outfile;
1308 1.1 christos callbacks_hold = callbacks;
1309 1.1 christos
1310 1.1 christos /* We want to call diff_run preserving any stdout and stderr
1311 1.1 christos callbacks, but discarding any callbacks to handle file output,
1312 1.1 christos since we want the file output to go to our temporary file.
1313 1.1 christos FIXME: We should use callbacks to just read it into a memory
1314 1.1 christos buffer; that's we do with the temporary file just below anyhow. */
1315 1.1 christos if (callbacks == NULL)
1316 1.1 christos my_callbacks_arg = NULL;
1317 1.1 christos else
1318 1.1 christos {
1319 1.1 christos my_callbacks = *callbacks;
1320 1.1 christos my_callbacks.write_output = NULL;
1321 1.1 christos my_callbacks.flush_output = NULL;
1322 1.1 christos my_callbacks_arg = &my_callbacks;
1323 1.1 christos }
1324 1.1 christos
1325 1.1 christos wstatus = diff_run (ap - argv, (char **) argv, diffout, my_callbacks_arg);
1326 1.1 christos
1327 1.1 christos outfile = outfile_hold;
1328 1.1 christos callbacks = callbacks_hold;
1329 1.1 christos
1330 1.1 christos if (wstatus == 2)
1331 1.1 christos diff3_fatal ("subsidiary diff failed");
1332 1.1 christos
1333 1.1 christos if (-1 == (fd = open (diffout, O_RDONLY)))
1334 1.1 christos diff3_fatal ("could not open temporary diff file");
1335 1.1 christos
1336 1.1 christos current_chunk_size = 8 * 1024;
1337 1.1 christos if (fstat (fd, &pipestat) == 0)
1338 1.1 christos current_chunk_size = max (current_chunk_size, STAT_BLOCKSIZE (pipestat));
1339 1.1 christos
1340 1.1 christos diff_result = xmalloc (current_chunk_size);
1341 1.1 christos total = 0;
1342 1.1 christos do {
1343 1.1 christos bytes = myread (fd,
1344 1.1 christos diff_result + total,
1345 1.1 christos current_chunk_size - total);
1346 1.1 christos total += bytes;
1347 1.1 christos if (total == current_chunk_size)
1348 1.1 christos {
1349 1.1 christos if (current_chunk_size < 2 * current_chunk_size)
1350 1.1 christos current_chunk_size = 2 * current_chunk_size;
1351 1.1 christos else if (current_chunk_size < (size_t) -1)
1352 1.1 christos current_chunk_size = (size_t) -1;
1353 1.1 christos else
1354 1.1 christos diff3_fatal ("files are too large to fit into memory");
1355 1.1 christos diff_result = xrealloc (diff_result, (current_chunk_size *= 2));
1356 1.1 christos }
1357 1.1 christos } while (bytes);
1358 1.1 christos
1359 1.1 christos if (total != 0 && diff_result[total-1] != '\n')
1360 1.1 christos diff3_fatal ("invalid diff format; incomplete last line");
1361 1.1 christos
1362 1.1 christos *output_placement = diff_result;
1363 1.1 christos
1364 1.1 christos if (close (fd) != 0)
1365 1.1 christos diff3_perror_with_exit ("pipe close");
1366 1.1 christos unlink (diffout);
1367 1.1 christos free( diffout );
1368 1.1 christos
1369 1.1 christos return diff_result + total;
1370 1.1 christos }
1371 1.1 christos
1372 1.1 christos
1373 1.1 christos /*
1374 1.1 christos * Scan a regular diff line (consisting of > or <, followed by a
1375 1.1 christos * space, followed by text (including nulls) up to a newline.
1376 1.1 christos *
1377 1.1 christos * This next routine began life as a macro and many parameters in it
1378 1.1 christos * are used as call-by-reference values.
1379 1.1 christos */
1380 1.1 christos static char *
1381 1.1 christos scan_diff_line (scan_ptr, set_start, set_length, limit, leadingchar)
1382 1.1 christos char *scan_ptr, **set_start;
1383 1.1 christos size_t *set_length;
1384 1.1 christos char *limit;
1385 1.1 christos int leadingchar;
1386 1.1 christos {
1387 1.1 christos char *line_ptr;
1388 1.1 christos
1389 1.1 christos if (!(scan_ptr[0] == leadingchar
1390 1.1 christos && scan_ptr[1] == ' '))
1391 1.1 christos diff3_fatal ("invalid diff format; incorrect leading line chars");
1392 1.1 christos
1393 1.1 christos *set_start = line_ptr = scan_ptr + 2;
1394 1.1 christos while (*line_ptr++ != '\n')
1395 1.1 christos ;
1396 1.1 christos
1397 1.1 christos /* Include newline if the original line ended in a newline,
1398 1.1 christos or if an edit script is being generated.
1399 1.1 christos Copy any missing newline message to stderr if an edit script is being
1400 1.1 christos generated, because edit scripts cannot handle missing newlines.
1401 1.1 christos Return the beginning of the next line. */
1402 1.1 christos *set_length = line_ptr - *set_start;
1403 1.1 christos if (line_ptr < limit && *line_ptr == '\\')
1404 1.1 christos {
1405 1.1 christos if (! edscript)
1406 1.1 christos {
1407 1.1 christos --*set_length;
1408 1.1 christos line_ptr++;
1409 1.1 christos while (*line_ptr++ != '\n')
1410 1.1 christos ;
1411 1.1 christos }
1412 1.1 christos else
1413 1.1 christos {
1414 1.1 christos char *serr;
1415 1.1 christos
1416 1.1 christos line_ptr++;
1417 1.1 christos serr = line_ptr;
1418 1.1 christos while (*line_ptr++ != '\n')
1419 1.1 christos ;
1420 1.1 christos line_ptr[-1] = '\0';
1421 1.1 christos diff_error ("%s", serr, 0);
1422 1.1 christos line_ptr[-1] = '\n';
1423 1.1 christos }
1424 1.1 christos }
1425 1.1 christos
1426 1.1 christos return line_ptr;
1427 1.1 christos }
1428 1.1 christos
1429 1.1 christos /*
1430 1.1 christos * This routine outputs a three way diff passed as a list of
1431 1.1 christos * diff3_block's.
1432 1.1 christos * The argument MAPPING is indexed by external file number (in the
1433 1.1 christos * argument list) and contains the internal file number (from the
1434 1.1 christos * diff passed). This is important because the user expects his
1435 1.1 christos * outputs in terms of the argument list number, and the diff passed
1436 1.1 christos * may have been done slightly differently (if the last argument
1437 1.1 christos * was "-", for example).
1438 1.1 christos * REV_MAPPING is the inverse of MAPPING.
1439 1.1 christos */
1440 1.1 christos static void
1441 1.1 christos output_diff3 (diff, mapping, rev_mapping)
1442 1.1 christos struct diff3_block *diff;
1443 1.1 christos int const mapping[3], rev_mapping[3];
1444 1.1 christos {
1445 1.1 christos int i;
1446 1.1 christos int oddoneout;
1447 1.1 christos char *cp;
1448 1.1 christos struct diff3_block *ptr;
1449 1.1 christos int line;
1450 1.1 christos size_t length;
1451 1.1 christos int dontprint;
1452 1.1 christos static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
1453 1.1 christos char const *line_prefix = tab_align_flag ? "\t" : " ";
1454 1.1 christos
1455 1.1 christos for (ptr = diff; ptr; ptr = D_NEXT (ptr))
1456 1.1 christos {
1457 1.1 christos char x[2];
1458 1.1 christos
1459 1.1 christos switch (ptr->correspond)
1460 1.1 christos {
1461 1.1 christos case DIFF_ALL:
1462 1.1 christos x[0] = '\0';
1463 1.1 christos dontprint = 3; /* Print them all */
1464 1.1 christos oddoneout = 3; /* Nobody's odder than anyone else */
1465 1.1 christos break;
1466 1.1 christos case DIFF_1ST:
1467 1.1 christos case DIFF_2ND:
1468 1.1 christos case DIFF_3RD:
1469 1.1 christos oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST];
1470 1.1 christos
1471 1.1 christos x[0] = oddoneout + '1';
1472 1.1 christos x[1] = '\0';
1473 1.1 christos dontprint = oddoneout==0;
1474 1.1 christos break;
1475 1.1 christos default:
1476 1.1 christos diff3_fatal ("internal error: invalid diff type passed to output");
1477 1.1 christos }
1478 1.1 christos printf_output ("====%s\n", x);
1479 1.1 christos
1480 1.1 christos /* Go 0, 2, 1 if the first and third outputs are equivalent. */
1481 1.1 christos for (i = 0; i < 3;
1482 1.1 christos i = (oddoneout == 1 ? skew_increment[i] : i + 1))
1483 1.1 christos {
1484 1.1 christos int realfile = mapping[i];
1485 1.1 christos int
1486 1.1 christos lowt = D_LOWLINE (ptr, realfile),
1487 1.1 christos hight = D_HIGHLINE (ptr, realfile);
1488 1.1 christos
1489 1.1 christos printf_output ("%d:", i + 1);
1490 1.1 christos switch (lowt - hight)
1491 1.1 christos {
1492 1.1 christos case 1:
1493 1.1 christos printf_output ("%da\n", lowt - 1);
1494 1.1 christos break;
1495 1.1 christos case 0:
1496 1.1 christos printf_output ("%dc\n", lowt);
1497 1.1 christos break;
1498 1.1 christos default:
1499 1.1 christos printf_output ("%d,%dc\n", lowt, hight);
1500 1.1 christos break;
1501 1.1 christos }
1502 1.1 christos
1503 1.1 christos if (i == dontprint) continue;
1504 1.1 christos
1505 1.1 christos if (lowt <= hight)
1506 1.3 christos {
1507 1.1 christos line = 0;
1508 1.1 christos do
1509 1.1 christos {
1510 1.1 christos printf_output ("%s", line_prefix);
1511 1.1 christos cp = D_RELNUM (ptr, realfile, line);
1512 1.1 christos length = D_RELLEN (ptr, realfile, line);
1513 1.1 christos write_output (cp, length);
1514 1.1 christos }
1515 1.1 christos while (++line < hight - lowt + 1);
1516 1.1 christos if (cp[length - 1] != '\n')
1517 1.1 christos printf_output ("\n\\ No newline at end of file\n");
1518 1.1 christos }
1519 1.1 christos }
1520 1.1 christos }
1521 1.1 christos }
1522 1.1 christos
1523 1.1 christos
1524 1.1 christos /*
1525 1.1 christos * Output the lines of B taken from FILENUM.
1526 1.1 christos * Double any initial '.'s; yield nonzero if any initial '.'s were doubled.
1527 1.1 christos */
1528 1.1 christos static int
1529 1.1 christos dotlines (b, filenum)
1530 1.1 christos struct diff3_block *b;
1531 1.1 christos int filenum;
1532 1.1 christos {
1533 1.1 christos int i;
1534 1.1 christos int leading_dot = 0;
1535 1.1 christos
1536 1.1 christos for (i = 0;
1537 1.1 christos i < D_NUMLINES (b, filenum);
1538 1.1 christos i++)
1539 1.1 christos {
1540 1.1 christos char *line = D_RELNUM (b, filenum, i);
1541 1.1 christos if (line[0] == '.')
1542 1.1 christos {
1543 1.1 christos leading_dot = 1;
1544 1.1 christos write_output (".", 1);
1545 1.1 christos }
1546 1.1 christos write_output (line, D_RELLEN (b, filenum, i));
1547 1.1 christos }
1548 1.1 christos
1549 1.1 christos return leading_dot;
1550 1.1 christos }
1551 1.1 christos
1552 1.1 christos /*
1553 1.1 christos * Output to OUTPUTFILE a '.' line. If LEADING_DOT is nonzero,
1554 1.1 christos * also output a command that removes initial '.'s
1555 1.1 christos * starting with line START and continuing for NUM lines.
1556 1.1 christos */
1557 1.1 christos static void
1558 1.1 christos undotlines (leading_dot, start, num)
1559 1.2 joerg int leading_dot, start, num;
1560 1.1 christos {
1561 1.1 christos write_output (".\n", 2);
1562 1.1 christos if (leading_dot)
1563 1.1 christos {
1564 1.2 joerg if (num == 1)
1565 1.1 christos printf_output ("%ds/^\\.//\n", start);
1566 1.1 christos else
1567 1.1 christos printf_output ("%d,%ds/^\\.//\n", start, start + num - 1);
1568 1.1 christos }
1569 1.1 christos }
1570 1.1 christos
1571 1.1 christos /*
1572 1.1 christos * This routine outputs a diff3 set of blocks as an ed script. This
1573 1.1 christos * script applies the changes between file's 2 & 3 to file 1. It
1574 1.1 christos * takes the precise format of the ed script to be output from global
1575 1.1 christos * variables set during options processing. Note that it does
1576 1.1 christos * destructive things to the set of diff3 blocks it is passed; it
1577 1.1 christos * reverses their order (this gets around the problems involved with
1578 1.1 christos * changing line numbers in an ed script).
1579 1.1 christos *
1580 1.1 christos * Note that this routine has the same problem of mapping as the last
1581 1.1 christos * one did; the variable MAPPING maps from file number according to
1582 1.1 christos * the argument list to file number according to the diff passed. All
1583 1.1 christos * files listed below are in terms of the argument list.
1584 1.1 christos * REV_MAPPING is the inverse of MAPPING.
1585 1.1 christos *
1586 1.1 christos * The arguments FILE0, FILE1 and FILE2 are the strings to print
1587 1.1 christos * as the names of the three files. These may be the actual names,
1588 1.1 christos * or may be the arguments specified with -L.
1589 1.1 christos *
1590 1.1 christos * Returns 1 if conflicts were found.
1591 1.1 christos */
1592 1.1 christos
1593 1.1 christos static int
1594 1.1 christos output_diff3_edscript (diff, mapping, rev_mapping, file0, file1, file2)
1595 1.1 christos struct diff3_block *diff;
1596 1.1 christos int const mapping[3], rev_mapping[3];
1597 1.1 christos char const *file0, *file1, *file2;
1598 1.1 christos {
1599 1.1 christos int leading_dot;
1600 1.1 christos int conflicts_found = 0, conflict;
1601 1.1 christos struct diff3_block *b;
1602 1.1 christos
1603 1.1 christos for (b = reverse_diff3_blocklist (diff); b; b = b->next)
1604 1.1 christos {
1605 1.1 christos /* Must do mapping correctly. */
1606 1.1 christos enum diff_type type
1607 1.1 christos = ((b->correspond == DIFF_ALL) ?
1608 1.1 christos DIFF_ALL :
1609 1.1 christos ((enum diff_type)
1610 1.1 christos (((int) DIFF_1ST)
1611 1.1 christos + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
1612 1.1 christos
1613 1.1 christos /* If we aren't supposed to do this output block, skip it. */
1614 1.1 christos switch (type)
1615 1.1 christos {
1616 1.1 christos default: continue;
1617 1.1 christos case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
1618 1.1 christos case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
1619 1.1 christos case DIFF_ALL: if (simple_only) continue; conflict = flagging; break;
1620 1.1 christos }
1621 1.1 christos
1622 1.1 christos if (conflict)
1623 1.1 christos {
1624 1.1 christos conflicts_found = 1;
1625 1.1 christos
1626 1.1 christos
1627 1.1 christos /* Mark end of conflict. */
1628 1.1 christos
1629 1.1 christos printf_output ("%da\n", D_HIGHLINE (b, mapping[FILE0]));
1630 1.1 christos leading_dot = 0;
1631 1.1 christos if (type == DIFF_ALL)
1632 1.1 christos {
1633 1.1 christos if (show_2nd)
1634 1.1 christos {
1635 1.1 christos /* Append lines from FILE1. */
1636 1.1 christos printf_output ("||||||| %s\n", file1);
1637 1.1 christos leading_dot = dotlines (b, mapping[FILE1]);
1638 1.1 christos }
1639 1.1 christos /* Append lines from FILE2. */
1640 1.1 christos printf_output ("=======\n");
1641 1.1 christos leading_dot |= dotlines (b, mapping[FILE2]);
1642 1.1 christos }
1643 1.1 christos printf_output (">>>>>>> %s\n", file2);
1644 1.1 christos undotlines (leading_dot,
1645 1.1 christos D_HIGHLINE (b, mapping[FILE0]) + 2,
1646 1.1 christos (D_NUMLINES (b, mapping[FILE1])
1647 1.1 christos + D_NUMLINES (b, mapping[FILE2]) + 1));
1648 1.1 christos
1649 1.1 christos
1650 1.1 christos /* Mark start of conflict. */
1651 1.1 christos
1652 1.1 christos printf_output ("%da\n<<<<<<< %s\n",
1653 1.1 christos D_LOWLINE (b, mapping[FILE0]) - 1,
1654 1.1 christos type == DIFF_ALL ? file0 : file1);
1655 1.1 christos leading_dot = 0;
1656 1.1 christos if (type == DIFF_2ND)
1657 1.1 christos {
1658 1.1 christos /* Prepend lines from FILE1. */
1659 1.1 christos leading_dot = dotlines (b, mapping[FILE1]);
1660 1.1 christos printf_output ("=======\n");
1661 1.1 christos }
1662 1.1 christos undotlines (leading_dot,
1663 1.1 christos D_LOWLINE (b, mapping[FILE0]) + 1,
1664 1.1 christos D_NUMLINES (b, mapping[FILE1]));
1665 1.1 christos }
1666 1.1 christos else if (D_NUMLINES (b, mapping[FILE2]) == 0)
1667 1.1 christos /* Write out a delete */
1668 1.1 christos {
1669 1.1 christos if (D_NUMLINES (b, mapping[FILE0]) == 1)
1670 1.1 christos printf_output ("%dd\n", D_LOWLINE (b, mapping[FILE0]));
1671 1.1 christos else
1672 1.1 christos printf_output ("%d,%dd\n",
1673 1.1 christos D_LOWLINE (b, mapping[FILE0]),
1674 1.1 christos D_HIGHLINE (b, mapping[FILE0]));
1675 1.1 christos }
1676 1.1 christos else
1677 1.1 christos /* Write out an add or change */
1678 1.1 christos {
1679 1.1 christos switch (D_NUMLINES (b, mapping[FILE0]))
1680 1.1 christos {
1681 1.1 christos case 0:
1682 1.1 christos printf_output ("%da\n", D_HIGHLINE (b, mapping[FILE0]));
1683 1.1 christos break;
1684 1.1 christos case 1:
1685 1.1 christos printf_output ("%dc\n", D_HIGHLINE (b, mapping[FILE0]));
1686 1.1 christos break;
1687 1.1 christos default:
1688 1.1 christos printf_output ("%d,%dc\n",
1689 1.1 christos D_LOWLINE (b, mapping[FILE0]),
1690 1.1 christos D_HIGHLINE (b, mapping[FILE0]));
1691 1.1 christos break;
1692 1.1 christos }
1693 1.1 christos
1694 1.1 christos undotlines (dotlines (b, mapping[FILE2]),
1695 1.1 christos D_LOWLINE (b, mapping[FILE0]),
1696 1.1 christos D_NUMLINES (b, mapping[FILE2]));
1697 1.1 christos }
1698 1.1 christos }
1699 1.1 christos if (finalwrite) printf_output ("w\nq\n");
1700 1.1 christos return conflicts_found;
1701 1.1 christos }
1702 1.1 christos
1703 1.1 christos /*
1704 1.1 christos * Read from INFILE and output to the standard output file a set of
1705 1.1 christos * diff3_ blocks DIFF as a merged file. This acts like 'ed file0
1706 1.1 christos * <[output_diff3_edscript]', except that it works even for binary
1707 1.1 christos * data or incomplete lines.
1708 1.1 christos *
1709 1.1 christos * As before, MAPPING maps from arg list file number to diff file number,
1710 1.1 christos * REV_MAPPING is its inverse,
1711 1.1 christos * and FILE0, FILE1, and FILE2 are the names of the files.
1712 1.1 christos *
1713 1.1 christos * Returns 1 if conflicts were found.
1714 1.1 christos */
1715 1.1 christos
1716 1.1 christos static int
1717 1.1 christos output_diff3_merge (infile, diff, mapping, rev_mapping,
1718 1.1 christos file0, file1, file2)
1719 1.1 christos FILE *infile;
1720 1.1 christos struct diff3_block *diff;
1721 1.1 christos int const mapping[3], rev_mapping[3];
1722 1.1 christos char const *file0, *file1, *file2;
1723 1.1 christos {
1724 1.1 christos int c, i;
1725 1.1 christos char cc;
1726 1.1 christos int conflicts_found = 0, conflict;
1727 1.1 christos struct diff3_block *b;
1728 1.1 christos int linesread = 0;
1729 1.1 christos
1730 1.1 christos for (b = diff; b; b = b->next)
1731 1.1 christos {
1732 1.1 christos /* Must do mapping correctly. */
1733 1.1 christos enum diff_type type
1734 1.1 christos = ((b->correspond == DIFF_ALL) ?
1735 1.1 christos DIFF_ALL :
1736 1.1 christos ((enum diff_type)
1737 1.1 christos (((int) DIFF_1ST)
1738 1.1 christos + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
1739 1.1 christos char const *format_2nd = "<<<<<<< %s\n";
1740 1.1 christos
1741 1.1 christos /* If we aren't supposed to do this output block, skip it. */
1742 1.1 christos switch (type)
1743 1.1 christos {
1744 1.1 christos default: continue;
1745 1.1 christos case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break;
1746 1.1 christos case DIFF_3RD: if (overlap_only) continue; conflict = 0; break;
1747 1.1 christos case DIFF_ALL: if (simple_only) continue; conflict = flagging;
1748 1.1 christos format_2nd = "||||||| %s\n";
1749 1.1 christos break;
1750 1.1 christos }
1751 1.1 christos
1752 1.1 christos /* Copy I lines from file 0. */
1753 1.1 christos i = D_LOWLINE (b, FILE0) - linesread - 1;
1754 1.1 christos linesread += i;
1755 1.1 christos while (0 <= --i)
1756 1.2 joerg do
1757 1.1 christos {
1758 1.1 christos c = getc (infile);
1759 1.1 christos if (c == EOF)
1760 1.1 christos {
1761 1.2 joerg if (ferror (infile))
1762 1.1 christos diff3_perror_with_exit ("input file");
1763 1.1 christos else if (feof (infile))
1764 1.1 christos diff3_fatal ("input file shrank");
1765 1.1 christos }
1766 1.1 christos cc = c;
1767 1.1 christos write_output (&cc, 1);
1768 1.1 christos }
1769 1.1 christos while (c != '\n');
1770 1.1 christos
1771 1.1 christos if (conflict)
1772 1.1 christos {
1773 1.1 christos conflicts_found = 1;
1774 1.1 christos
1775 1.1 christos if (type == DIFF_ALL)
1776 1.1 christos {
1777 1.1 christos /* Put in lines from FILE0 with bracket. */
1778 1.1 christos printf_output ("<<<<<<< %s\n", file0);
1779 1.1 christos for (i = 0;
1780 1.1 christos i < D_NUMLINES (b, mapping[FILE0]);
1781 1.1 christos i++)
1782 1.1 christos write_output (D_RELNUM (b, mapping[FILE0], i),
1783 1.1 christos D_RELLEN (b, mapping[FILE0], i));
1784 1.1 christos }
1785 1.1 christos
1786 1.1 christos if (show_2nd)
1787 1.1 christos {
1788 1.1 christos /* Put in lines from FILE1 with bracket. */
1789 1.1 christos printf_output (format_2nd, file1);
1790 1.1 christos for (i = 0;
1791 1.1 christos i < D_NUMLINES (b, mapping[FILE1]);
1792 1.1 christos i++)
1793 1.1 christos write_output (D_RELNUM (b, mapping[FILE1], i),
1794 1.1 christos D_RELLEN (b, mapping[FILE1], i));
1795 1.1 christos }
1796 1.1 christos
1797 1.1 christos printf_output ("=======\n");
1798 1.1 christos }
1799 1.1 christos
1800 1.1 christos /* Put in lines from FILE2. */
1801 1.1 christos for (i = 0;
1802 1.1 christos i < D_NUMLINES (b, mapping[FILE2]);
1803 1.1 christos i++)
1804 1.1 christos write_output (D_RELNUM (b, mapping[FILE2], i),
1805 1.1 christos D_RELLEN (b, mapping[FILE2], i));
1806 1.1 christos
1807 1.1 christos if (conflict)
1808 1.1 christos printf_output (">>>>>>> %s\n", file2);
1809 1.1 christos
1810 1.1 christos /* Skip I lines in file 0. */
1811 1.1 christos i = D_NUMLINES (b, FILE0);
1812 1.2 joerg linesread += i;
1813 1.1 christos while (0 <= --i)
1814 1.1 christos while ((c = getc (infile)) != '\n')
1815 1.1 christos if (c == EOF)
1816 1.1 christos {
1817 1.1 christos if (ferror (infile))
1818 1.1 christos diff3_perror_with_exit ("input file");
1819 1.1 christos else if (feof (infile))
1820 1.1 christos {
1821 1.2 joerg if (i || b->next)
1822 1.1 christos diff3_fatal ("input file shrank");
1823 1.1 christos return conflicts_found;
1824 1.1 christos }
1825 1.1 christos }
1826 1.1 christos }
1827 1.1 christos /* Copy rest of common file. */
1828 1.1 christos while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile)))
1829 1.1 christos {
1830 1.1 christos cc = c;
1831 1.1 christos write_output (&cc, 1);
1832 1.1 christos }
1833 1.1 christos return conflicts_found;
1834 1.1 christos }
1835 1.1 christos
1836 1.1 christos /*
1837 1.1 christos * Reverse the order of the list of diff3 blocks.
1838 1.1 christos */
1839 1.1 christos static struct diff3_block *
1840 1.1 christos reverse_diff3_blocklist (diff)
1841 1.1 christos struct diff3_block *diff;
1842 1.1 christos {
1843 1.1 christos register struct diff3_block *tmp, *next, *prev;
1844 1.1 christos
1845 1.1 christos for (tmp = diff, prev = 0; tmp; tmp = next)
1846 1.1 christos {
1847 1.1 christos next = tmp->next;
1848 1.1 christos tmp->next = prev;
1849 1.1 christos prev = tmp;
1850 1.1 christos }
1851 1.1 christos
1852 1.1 christos return prev;
1853 1.1 christos }
1854 1.1 christos
1855 1.1 christos static size_t
1857 1.1 christos myread (fd, ptr, size)
1858 1.1 christos int fd;
1859 1.1 christos char *ptr;
1860 1.1 christos size_t size;
1861 1.1 christos {
1862 1.1 christos ssize_t result = read (fd, ptr, size);
1863 1.1 christos if (result == -1)
1864 1.1 christos diff3_perror_with_exit ("read failed");
1865 1.1 christos return (size_t)result;
1866 1.1 christos }
1867 1.1 christos
1868 1.1 christos static void
1870 1.1 christos diff3_fatal (string)
1871 1.1 christos char const *string;
1872 1.1 christos {
1873 1.1 christos diff_error ("%s", string, 0);
1874 1.1 christos DIFF3_ABORT (2);
1875 1.1 christos }
1876 1.1 christos
1877 1.1 christos static void
1878 1.1 christos diff3_perror_with_exit (string)
1879 1.1 christos char const *string;
1880 1.1 christos {
1881 1.1 christos perror_with_name (string);
1882 1.1 christos DIFF3_ABORT (2);
1883 1.1 christos }
1884 1.1 christos
1885 1.1 christos static void
1886 1.1 christos initialize_main (argcp, argvp)
1887 1.1 christos int *argcp;
1888 1.1 christos char ***argvp;
1889 1.1 christos {
1890 1.1 christos always_text = 0;
1891 1.1 christos edscript = 0;
1892 1.1 christos flagging = 0;
1893 1.1 christos tab_align_flag = 0;
1894 1.1 christos simple_only = 0;
1895 1.1 christos overlap_only = 0;
1896 1.1 christos show_2nd = 0;
1897 1.1 christos finalwrite = 0;
1898 1.1 christos merge = 0;
1899 1.1 christos diff_program_name = (*argvp)[0];
1900 1.1 christos outfile = NULL;
1901 1.1 christos }
1902 1.1 christos
1903 1.1 christos static void
1904 1.1 christos free_diff_blocks(p)
1905 1.1 christos struct diff_block *p;
1906 1.1 christos {
1907 1.1 christos register struct diff_block *next;
1908 1.1 christos
1909 1.1 christos while (p)
1910 1.1 christos {
1911 1.1 christos next = p->next;
1912 1.1 christos if (p->lines[0]) free(p->lines[0]);
1913 1.1 christos if (p->lines[1]) free(p->lines[1]);
1914 1.1 christos if (p->lengths[0]) free(p->lengths[0]);
1915 1.1 christos if (p->lengths[1]) free(p->lengths[1]);
1916 1.1 christos free(p);
1917 1.1 christos p = next;
1918 1.1 christos }
1919 1.1 christos }
1920 1.1 christos
1921 1.1 christos static void
1922 1.1 christos free_diff3_blocks(p)
1923 1.1 christos struct diff3_block *p;
1924 1.1 christos {
1925 1.1 christos register struct diff3_block *next;
1926 1.1 christos
1927 1.1 christos while (p)
1928 1.1 christos {
1929 1.1 christos next = p->next;
1930 1.1 christos if (p->lines[0]) free(p->lines[0]);
1931 1.1 christos if (p->lines[1]) free(p->lines[1]);
1932 1.1 christos if (p->lines[2]) free(p->lines[2]);
1933 1.1 christos if (p->lengths[0]) free(p->lengths[0]);
1934 if (p->lengths[1]) free(p->lengths[1]);
1935 if (p->lengths[2]) free(p->lengths[2]);
1936 free(p);
1937 p = next;
1938 }
1939 }
1940