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