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