/* Three way file comparison program (diff3) for Project GNU. Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Written by Randy Smith */ #include "system.h"#include <stdio.h>#include <signal.h>#include "getopt.h" extern char const version_string[]; /* * Internal data structures and macros for the diff3 program; includes * data structures for both diff3 diffs and normal diffs. */ /* Different files within a three way diff. */#define FILE0 0#define FILE1 1#define FILE2 2 /* * A three way diff is built from two two-way diffs; the file which * the two two-way diffs share is: */#define FILEC FILE2 /* * Different files within a two way diff. * FC is the common file, FO the other file. */#define FO 0#define FC 1 /* The ranges are indexed by */#define START 0#define END 1 enum diff_type { ERROR, /* Should not be used */ ADD, /* Two way diff add */ CHANGE, /* Two way diff change */ DELETE, /* Two way diff delete */ DIFF_ALL, /* All three are different */ DIFF_1ST, /* Only the first is different */ DIFF_2ND, /* Only the second */ DIFF_3RD /* Only the third */}; /* Two way diff */struct diff_block { int ranges[2][2]; /* Ranges are inclusive */ char **lines[2]; /* The actual lines (may contain nulls) */ size_t *lengths[2]; /* Line lengths (including newlines, if any) */ struct diff_block *next;}; /* Three way diff */ struct diff3_block { enum diff_type correspond; /* Type of diff */ int ranges[3][2]; /* Ranges are inclusive */ char **lines[3]; /* The actual lines (may contain nulls) */ size_t *lengths[3]; /* Line lengths (including newlines, if any) */ struct diff3_block *next;}; /* * Access the ranges on a diff block. */#define D_LOWLINE(diff, filenum) \ ((diff)->ranges[filenum][START])#define D_HIGHLINE(diff, filenum) \ ((diff)->ranges[filenum][END])#define D_NUMLINES(diff, filenum) \ (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1) /* * Access the line numbers in a file in a diff by relative line * numbers (i.e. line number within the diff itself). Note that these * are lvalues and can be used for assignment. */#define D_RELNUM(diff, filenum, linenum) \ ((diff)->lines[filenum][linenum])#define D_RELLEN(diff, filenum, linenum) \ ((diff)->lengths[filenum][linenum]) /* * And get at them directly, when that should be necessary. */#define D_LINEARRAY(diff, filenum) \ ((diff)->lines[filenum])#define D_LENARRAY(diff, filenum) \ ((diff)->lengths[filenum]) /* * Next block. */#define D_NEXT(diff) ((diff)->next) /* * Access the type of a diff3 block. */#define D3_TYPE(diff) ((diff)->correspond) /* * Line mappings based on diffs. The first maps off the top of the * diff, the second off of the bottom. */#define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \ ((lineno) \ - D_HIGHLINE ((diff), (fromfile)) \ + D_HIGHLINE ((diff), (tofile))) #define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \ ((lineno) \ - D_LOWLINE ((diff), (fromfile)) \ + D_LOWLINE ((diff), (tofile))) /* * General memory allocation function. */#define ALLOCATE(number, type) \ (type *) xmalloc ((number) * sizeof (type))/* Options variables for flags set on command line. */ /* If nonzero, treat all files as text files, never as binary. */static int always_text; /* If nonzero, write out an ed script instead of the standard diff3 format. */static int edscript; /* If nonzero, in the case of overlapping diffs (type DIFF_ALL), preserve the lines which would normally be deleted from file 1 with a special flagging mechanism. */static int flagging; /* Number of lines to keep in identical prefix and suffix. */static int horizon_lines = 10; /* Use a tab to align output lines (-T). */static int tab_align_flag; /* If nonzero, do not output information for overlapping diffs. */static int simple_only; /* If nonzero, do not output information for non-overlapping diffs. */static int overlap_only; /* If nonzero, show information for DIFF_2ND diffs. */static int show_2nd; /* If nonzero, include `:wq' at the end of the script to write out the file being edited. */static int finalwrite; /* If nonzero, output a merged file. */static int merge; static char *program_name; static VOID *xmalloc PARAMS((size_t));static VOID *xrealloc PARAMS((VOID *, size_t)); static char *read_diff PARAMS((char const *, char const *, char **));static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int));static enum diff_type process_diff_control PARAMS((char **, struct diff_block *));static int compare_line_list PARAMS((char * const[], size_t const[], char * const[], size_t const[], int));static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int));static int dotlines PARAMS((FILE *, struct diff3_block *, int));static int output_diff3_edscript PARAMS((FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));static int output_diff3_merge PARAMS((FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));static size_t myread PARAMS((int, char *, size_t));static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int));static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *));static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *));static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *));static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **));static void check_stdout PARAMS((void));static void fatal PARAMS((char const *));static void output_diff3 PARAMS((FILE *, struct diff3_block *, int const[3], int const[3]));static void perror_with_exit PARAMS((char const *));static void try_help PARAMS((char const *));static void undotlines PARAMS((FILE *, int, int, int));static void usage PARAMS((void)); static char const diff_program[] = DIFF_PROGRAM; static struct option const longopts[] ={ {"text", 0, 0, 'a'}, {"show-all", 0, 0, 'A'}, {"ed", 0, 0, 'e'}, {"show-overlap", 0, 0, 'E'}, {"label", 1, 0, 'L'}, {"merge", 0, 0, 'm'}, {"initial-tab", 0, 0, 'T'}, {"overlap-only", 0, 0, 'x'}, {"easy-only", 0, 0, '3'}, {"version", 0, 0, 'v'}, {"help", 0, 0, 129}, {0, 0, 0, 0}}; /* * Main program. Calls diff twice on two pairs of input files, * combines the two diffs, and outputs them. */intmain (argc, argv) int argc; char **argv;{ int c, i; int mapping[3]; int rev_mapping[3]; int incompat = 0; int conflicts_found; struct diff_block *thread0, *thread1, *last_block; struct diff3_block *diff3; int tag_count = 0; char *tag_strings[3]; char *commonname; char **file; struct stat statb; initialize_main (&argc, &argv); program_name = argv[0]; while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF) { switch (c) { case 'a': always_text = 1; break; case 'A': show_2nd = 1; flagging = 1; incompat++; break; case 'x': overlap_only = 1; incompat++; break; case '3': simple_only = 1; incompat++; break; case 'i': finalwrite = 1; break; case 'm': merge = 1; break; case 'X': overlap_only = 1; /* Falls through */ case 'E': flagging = 1; /* Falls through */ case 'e': incompat++; break; case 'T': tab_align_flag = 1; break; case 'v': printf ("diff3 - GNU diffutils version %s\n", version_string); exit (0); case 129: usage (); check_stdout (); exit (0); case 'L': /* Handle up to three -L options. */ if (tag_count < 3) { tag_strings[tag_count++] = optarg; break; } try_help ("Too many labels were given. The limit is 3."); default: try_help (0); } } edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */ show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */ flagging |= ~incompat & merge; if (incompat > 1 /* Ensure at most one of -AeExX3. */ || finalwrite & merge /* -i -m would rewrite input file. */ || (tag_count && ! flagging)) /* -L requires one of -AEX. */ try_help ("incompatible options"); if (argc - optind != 3) try_help (argc - optind < 3 ? "missing operand" : "extra operand"); file = &argv[optind]; for (i = tag_count; i < 3; i++) tag_strings[i] = file[i]; /* Always compare file1 to file2, even if file2 is "-". This is needed for -mAeExX3. Using the file0 as the common file would produce wrong results, because if the file0-file1 diffs didn't line up with the file0-file2 diffs (which is entirely possible since we don't use diff's -n option), diff3 might report phantom changes from file1 to file2. */ if (strcmp (file[2], "-") == 0) { /* Sigh. We've got standard input as the last arg. We can't call diff twice on stdin. Use the middle arg as the common file instead. */ if (strcmp (file[0], "-") == 0 || strcmp (file[1], "-") == 0) fatal ("`-' specified for more than one input file"); mapping[0] = 0; mapping[1] = 2; mapping[2] = 1; } else { /* Normal, what you'd expect */ mapping[0] = 0; mapping[1] = 1; mapping[2] = 2; } for (i = 0; i < 3; i++) rev_mapping[mapping[i]] = i; for (i = 0; i < 3; i++) if (strcmp (file[i], "-") != 0) { if (stat (file[i], &statb) < 0) perror_with_exit (file[i]); else if (S_ISDIR(statb.st_mode)) { fprintf (stderr, "%s: %s: Is a directory\n", program_name, file[i]); exit (2); } } #if !defined(SIGCHLD) && defined(SIGCLD)#define SIGCHLD SIGCLD#endif#ifdef SIGCHLD /* System V fork+wait does not work if SIGCHLD is ignored. */ signal (SIGCHLD, SIG_DFL);#endif commonname = file[rev_mapping[FILEC]]; thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block); if (thread1) for (i = 0; i < 2; i++) { horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i)); horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i)); } thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block); diff3 = make_3way_diff (thread0, thread1); if (edscript) conflicts_found = output_diff3_edscript (stdout, diff3, mapping, rev_mapping, tag_strings[0], tag_strings[1], tag_strings[2]); else if (merge) { if (! freopen (file[rev_mapping[FILE0]], "r", stdin)) perror_with_exit (file[rev_mapping[FILE0]]); conflicts_found = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping, tag_strings[0], tag_strings[1], tag_strings[2]); if (ferror (stdin)) fatal ("read error"); } else { output_diff3 (stdout, diff3, mapping, rev_mapping); conflicts_found = 0; } check_stdout (); exit (conflicts_found); return conflicts_found;} static voidtry_help (reason) char const *reason;{ if (reason) fprintf (stderr, "%s: %s\n", program_name, reason); fprintf (stderr, "%s: Try `%s --help' for more information.\n", program_name, program_name); exit (2);} static voidcheck_stdout (){ if (ferror (stdout) || fclose (stdout) != 0) fatal ("write error");} /* * Explain, patiently and kindly, how to use this program. */static voidusage (){ printf ("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n\n", program_name); printf ("%s", "\ -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\ -E --show-overlap Output unmerged changes, bracketing conflicts.\n\ -A --show-all Output all changes, bracketing conflicts.\n\ -x --overlap-only Output overlapping changes.\n\ -X Output overlapping changes, bracketing them.\n\ -3 --easy-only Output unmerged nonoverlapping changes.\n\n"); printf ("%s", "\ -m --merge Output merged file instead of ed script (default -A).\n\ -L LABEL --label=LABEL Use LABEL instead of file name.\n\ -i Append `w' and `q' commands to ed scripts.\n\ -a --text Treat all files as text.\n\ -T --initial-tab Make tabs line up by prepending a tab.\n\n"); printf ("%s", "\ -v --version Output version info.\n\ --help Output this help.\n\n"); printf ("If a FILE is `-', read standard input.\n");}/* * Routines that combine the two diffs together into one. The * algorithm used follows: * * File2 is shared in common between the two diffs. * Diff02 is the diff between 0 and 2. * Diff12 is the diff between 1 and 2. * * 1) Find the range for the first block in File2. * a) Take the lowest of the two ranges (in File2) in the two * current blocks (one from each diff) as being the low * water mark. Assign the upper end of this block as * being the high water mark and move the current block up * one. Mark the block just moved over as to be used. * b) Check the next block in the diff that the high water * mark is *not* from. * * *If* the high water mark is above * the low end of the range in that block, * * mark that block as to be used and move the current * block up. Set the high water mark to the max of * the high end of this block and the current. Repeat b. * * 2) Find the corresponding ranges in File0 (from the blocks * in diff02; line per line outside of diffs) and in File1. * Create a diff3_block, reserving space as indicated by the ranges. * * 3) Copy all of the pointers for file2 in. At least for now, * do memcmp's between corresponding strings in the two diffs. * * 4) Copy all of the pointers for file0 and 1 in. Get what you * need from file2 (when there isn't a diff block, it's * identical to file2 within the range between diff blocks). * * 5) If the diff blocks you used came from only one of the two * strings of diffs, then that file (i.e. the one other than * the common file in that diff) is the odd person out. If you used * diff blocks from both sets, check to see if files 0 and 1 match: * * Same number of lines? If so, do a set of memcmp's (if a * memcmp matches; copy the pointer over; it'll be easier later * if you have to do any compares). If they match, 0 & 1 are * the same. If not, all three different. * * Then you do it again, until you run out of blocks. * */ /*Lines 1–500 of 1778. Load more
/* Three way file comparison program (diff3) for Project GNU. Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Written by Randy Smith */ #include "system.h" #include <stdio.h> #include <signal.h> #include "getopt.h" extern char const version_string[]; /* * Internal data structures and macros for the diff3 program; includes * data structures for both diff3 diffs and normal diffs. */ /* Different files within a three way diff. */ #define FILE0 0 #define FILE1 1 #define FILE2 2 /* * A three way diff is built from two two-way diffs; the file which * the two two-way diffs share is: */ #define FILEC FILE2 /* * Different files within a two way diff. * FC is the common file, FO the other file. */ #define FO 0 #define FC 1 /* The ranges are indexed by */ #define START 0 #define END 1 enum diff_type { ERROR, /* Should not be used */ ADD, /* Two way diff add */ CHANGE, /* Two way diff change */ DELETE, /* Two way diff delete */ DIFF_ALL, /* All three are different */ DIFF_1ST, /* Only the first is different */ DIFF_2ND, /* Only the second */ DIFF_3RD /* Only the third */ }; /* Two way diff */ struct diff_block { int ranges[2][2]; /* Ranges are inclusive */ char **lines[2]; /* The actual lines (may contain nulls) */ size_t *lengths[2]; /* Line lengths (including newlines, if any) */ struct diff_block *next; }; /* Three way diff */ struct diff3_block { enum diff_type correspond; /* Type of diff */ int ranges[3][2]; /* Ranges are inclusive */ char **lines[3]; /* The actual lines (may contain nulls) */ size_t *lengths[3]; /* Line lengths (including newlines, if any) */ struct diff3_block *next; }; /* * Access the ranges on a diff block. */ #define D_LOWLINE(diff, filenum) \ ((diff)->ranges[filenum][START]) #define D_HIGHLINE(diff, filenum) \ ((diff)->ranges[filenum][END]) #define D_NUMLINES(diff, filenum) \ (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1) /* * Access the line numbers in a file in a diff by relative line * numbers (i.e. line number within the diff itself). Note that these * are lvalues and can be used for assignment. */ #define D_RELNUM(diff, filenum, linenum) \ ((diff)->lines[filenum][linenum]) #define D_RELLEN(diff, filenum, linenum) \ ((diff)->lengths[filenum][linenum]) /* * And get at them directly, when that should be necessary. */ #define D_LINEARRAY(diff, filenum) \ ((diff)->lines[filenum]) #define D_LENARRAY(diff, filenum) \ ((diff)->lengths[filenum]) /* * Next block. */ #define D_NEXT(diff) ((diff)->next) /* * Access the type of a diff3 block. */ #define D3_TYPE(diff) ((diff)->correspond) /* * Line mappings based on diffs. The first maps off the top of the * diff, the second off of the bottom. */ #define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \ ((lineno) \ - D_HIGHLINE ((diff), (fromfile)) \ + D_HIGHLINE ((diff), (tofile))) #define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \ ((lineno) \ - D_LOWLINE ((diff), (fromfile)) \ + D_LOWLINE ((diff), (tofile))) /* * General memory allocation function. */ #define ALLOCATE(number, type) \ (type *) xmalloc ((number) * sizeof (type)) /* Options variables for flags set on command line. */ /* If nonzero, treat all files as text files, never as binary. */ static int always_text; /* If nonzero, write out an ed script instead of the standard diff3 format. */ static int edscript; /* If nonzero, in the case of overlapping diffs (type DIFF_ALL), preserve the lines which would normally be deleted from file 1 with a special flagging mechanism. */ static int flagging; /* Number of lines to keep in identical prefix and suffix. */ static int horizon_lines = 10; /* Use a tab to align output lines (-T). */ static int tab_align_flag; /* If nonzero, do not output information for overlapping diffs. */ static int simple_only; /* If nonzero, do not output information for non-overlapping diffs. */ static int overlap_only; /* If nonzero, show information for DIFF_2ND diffs. */ static int show_2nd; /* If nonzero, include `:wq' at the end of the script to write out the file being edited. */ static int finalwrite; /* If nonzero, output a merged file. */ static int merge; static char *program_name; static VOID *xmalloc PARAMS((size_t)); static VOID *xrealloc PARAMS((VOID *, size_t)); static char *read_diff PARAMS((char const *, char const *, char **)); static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int)); static enum diff_type process_diff_control PARAMS((char **, struct diff_block *)); static int compare_line_list PARAMS((char * const[], size_t const[], char * const[], size_t const[], int)); static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int)); static int dotlines PARAMS((FILE *, struct diff3_block *, int)); static int output_diff3_edscript PARAMS((FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *)); static int output_diff3_merge PARAMS((FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *)); static size_t myread PARAMS((int, char *, size_t)); static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int)); static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *)); static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *)); static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *)); static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **)); static void check_stdout PARAMS((void)); static void fatal PARAMS((char const *)); static void output_diff3 PARAMS((FILE *, struct diff3_block *, int const[3], int const[3])); static void perror_with_exit PARAMS((char const *)); static void try_help PARAMS((char const *)); static void undotlines PARAMS((FILE *, int, int, int)); static void usage PARAMS((void)); static char const diff_program[] = DIFF_PROGRAM; static struct option const longopts[] = { {"text", 0, 0, 'a'}, {"show-all", 0, 0, 'A'}, {"ed", 0, 0, 'e'}, {"show-overlap", 0, 0, 'E'}, {"label", 1, 0, 'L'}, {"merge", 0, 0, 'm'}, {"initial-tab", 0, 0, 'T'}, {"overlap-only", 0, 0, 'x'}, {"easy-only", 0, 0, '3'}, {"version", 0, 0, 'v'}, {"help", 0, 0, 129}, {0, 0, 0, 0} }; /* * Main program. Calls diff twice on two pairs of input files, * combines the two diffs, and outputs them. */ int main (argc, argv) int argc; char **argv; { int c, i; int mapping[3]; int rev_mapping[3]; int incompat = 0; int conflicts_found; struct diff_block *thread0, *thread1, *last_block; struct diff3_block *diff3; int tag_count = 0; char *tag_strings[3]; char *commonname; char **file; struct stat statb; initialize_main (&argc, &argv); program_name = argv[0]; while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF) { switch (c) { case 'a': always_text = 1; break; case 'A': show_2nd = 1; flagging = 1; incompat++; break; case 'x': overlap_only = 1; incompat++; break; case '3': simple_only = 1; incompat++; break; case 'i': finalwrite = 1; break; case 'm': merge = 1; break; case 'X': overlap_only = 1; /* Falls through */ case 'E': flagging = 1; /* Falls through */ case 'e': incompat++; break; case 'T': tab_align_flag = 1; break; case 'v': printf ("diff3 - GNU diffutils version %s\n", version_string); exit (0); case 129: usage (); check_stdout (); exit (0); case 'L': /* Handle up to three -L options. */ if (tag_count < 3) { tag_strings[tag_count++] = optarg; break; } try_help ("Too many labels were given. The limit is 3."); default: try_help (0); } } edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */ show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */ flagging |= ~incompat & merge; if (incompat > 1 /* Ensure at most one of -AeExX3. */ || finalwrite & merge /* -i -m would rewrite input file. */ || (tag_count && ! flagging)) /* -L requires one of -AEX. */ try_help ("incompatible options"); if (argc - optind != 3) try_help (argc - optind < 3 ? "missing operand" : "extra operand"); file = &argv[optind]; for (i = tag_count; i < 3; i++) tag_strings[i] = file[i]; /* Always compare file1 to file2, even if file2 is "-". This is needed for -mAeExX3. Using the file0 as the common file would produce wrong results, because if the file0-file1 diffs didn't line up with the file0-file2 diffs (which is entirely possible since we don't use diff's -n option), diff3 might report phantom changes from file1 to file2. */ if (strcmp (file[2], "-") == 0) { /* Sigh. We've got standard input as the last arg. We can't call diff twice on stdin. Use the middle arg as the common file instead. */ if (strcmp (file[0], "-") == 0 || strcmp (file[1], "-") == 0) fatal ("`-' specified for more than one input file"); mapping[0] = 0; mapping[1] = 2; mapping[2] = 1; } else { /* Normal, what you'd expect */ mapping[0] = 0; mapping[1] = 1; mapping[2] = 2; } for (i = 0; i < 3; i++) rev_mapping[mapping[i]] = i; for (i = 0; i < 3; i++) if (strcmp (file[i], "-") != 0) { if (stat (file[i], &statb) < 0) perror_with_exit (file[i]); else if (S_ISDIR(statb.st_mode)) { fprintf (stderr, "%s: %s: Is a directory\n", program_name, file[i]); exit (2); } } #if !defined(SIGCHLD) && defined(SIGCLD) #define SIGCHLD SIGCLD #endif #ifdef SIGCHLD /* System V fork+wait does not work if SIGCHLD is ignored. */ signal (SIGCHLD, SIG_DFL); #endif commonname = file[rev_mapping[FILEC]]; thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block); if (thread1) for (i = 0; i < 2; i++) { horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i)); horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i)); } thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block); diff3 = make_3way_diff (thread0, thread1); if (edscript) conflicts_found = output_diff3_edscript (stdout, diff3, mapping, rev_mapping, tag_strings[0], tag_strings[1], tag_strings[2]); else if (merge) { if (! freopen (file[rev_mapping[FILE0]], "r", stdin)) perror_with_exit (file[rev_mapping[FILE0]]); conflicts_found = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping, tag_strings[0], tag_strings[1], tag_strings[2]); if (ferror (stdin)) fatal ("read error"); } else { output_diff3 (stdout, diff3, mapping, rev_mapping); conflicts_found = 0; } check_stdout (); exit (conflicts_found); return conflicts_found; } static void try_help (reason) char const *reason; { if (reason) fprintf (stderr, "%s: %s\n", program_name, reason); fprintf (stderr, "%s: Try `%s --help' for more information.\n", program_name, program_name); exit (2); } static void check_stdout () { if (ferror (stdout) || fclose (stdout) != 0) fatal ("write error"); } /* * Explain, patiently and kindly, how to use this program. */ static void usage () { printf ("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n\n", program_name); printf ("%s", "\ -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\ -E --show-overlap Output unmerged changes, bracketing conflicts.\n\ -A --show-all Output all changes, bracketing conflicts.\n\ -x --overlap-only Output overlapping changes.\n\ -X Output overlapping changes, bracketing them.\n\ -3 --easy-only Output unmerged nonoverlapping changes.\n\n"); printf ("%s", "\ -m --merge Output merged file instead of ed script (default -A).\n\ -L LABEL --label=LABEL Use LABEL instead of file name.\n\ -i Append `w' and `q' commands to ed scripts.\n\ -a --text Treat all files as text.\n\ -T --initial-tab Make tabs line up by prepending a tab.\n\n"); printf ("%s", "\ -v --version Output version info.\n\ --help Output this help.\n\n"); printf ("If a FILE is `-', read standard input.\n"); } /* * Routines that combine the two diffs together into one. The * algorithm used follows: * * File2 is shared in common between the two diffs. * Diff02 is the diff between 0 and 2. * Diff12 is the diff between 1 and 2. * * 1) Find the range for the first block in File2. * a) Take the lowest of the two ranges (in File2) in the two * current blocks (one from each diff) as being the low * water mark. Assign the upper end of this block as * being the high water mark and move the current block up * one. Mark the block just moved over as to be used. * b) Check the next block in the diff that the high water * mark is *not* from. * * *If* the high water mark is above * the low end of the range in that block, * * mark that block as to be used and move the current * block up. Set the high water mark to the max of * the high end of this block and the current. Repeat b. * * 2) Find the corresponding ranges in File0 (from the blocks * in diff02; line per line outside of diffs) and in File1. * Create a diff3_block, reserving space as indicated by the ranges. * * 3) Copy all of the pointers for file2 in. At least for now, * do memcmp's between corresponding strings in the two diffs. * * 4) Copy all of the pointers for file0 and 1 in. Get what you * need from file2 (when there isn't a diff block, it's * identical to file2 within the range between diff blocks). * * 5) If the diff blocks you used came from only one of the two * strings of diffs, then that file (i.e. the one other than * the common file in that diff) is the odd person out. If you used * diff blocks from both sets, check to see if files 0 and 1 match: * * Same number of lines? If so, do a set of memcmp's (if a * memcmp matches; copy the pointer over; it'll be easier later * if you have to do any compares). If they match, 0 & 1 are * the same. If not, all three different. * * Then you do it again, until you run out of blocks. * */ /*