⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 diff3.c

📁 制作2.6内核的CLFS时 使用的diffutils-2.8.7.tar.gz包
💻 C
📖 第 1 页 / 共 4 页
字号:
/* diff3 - compare three files line by line   Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1998, 2001,   2002, 2004 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; see the file COPYING.   If not, write to the Free Software Foundation,   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */#include "system.h"#include "paths.h"#include <stdio.h>#include <unlocked-io.h>#include <c-stack.h>#include <cmpbuf.h>#include <error.h>#include <exitfail.h>#include <file-type.h>#include <getopt.h>#include <inttostr.h>#include <quotesys.h>#include <version-etc.h>#include <xalloc.h>/* 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	RANGE_START	0#define	RANGE_END	1enum 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 {  lin 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 */  lin 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][RANGE_START])#define	D_HIGHLINE(diff, filenum)	\  ((diff)->ranges[filenum][RANGE_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, linenum)	\  ((linenum)						\   - D_HIGHLINE ((diff), (fromfile))			\   + D_HIGHLINE ((diff), (tofile)))#define	D_LOW_MAPLINE(diff, fromfile, tofile, linenum)	\  ((linenum)						\   - D_LOWLINE ((diff), (fromfile))			\   + D_LOWLINE ((diff), (tofile)))/* Options variables for flags set on command line.  *//* If nonzero, treat all files as text files, never as binary.  */static bool text;/* Remove trailing carriage returns from input.  */static bool strip_trailing_cr;/* If nonzero, write out an ed script instead of the standard diff3 format.  */static bool 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 bool flagging;/* Use a tab to align output lines (-T).  */static bool initial_tab;/* If nonzero, do not output information for overlapping diffs.  */static bool simple_only;/* If nonzero, do not output information for non-overlapping diffs.  */static bool overlap_only;/* If nonzero, show information for DIFF_2ND diffs.  */static bool show_2nd;/* If nonzero, include `:wq' at the end of the script   to write out the file being edited.   */static bool finalwrite;/* If nonzero, output a merged file.  */static bool merge;char *program_name;static char *read_diff (char const *, char const *, char **);static char *scan_diff_line (char *, char **, size_t *, char *, char);static enum diff_type process_diff_control (char **, struct diff_block *);static bool compare_line_list (char * const[], size_t const[], char * const[], size_t const[], lin);static bool copy_stringlist (char * const[], size_t const[], char *[], size_t[], lin);static bool output_diff3_edscript (FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);static bool output_diff3_merge (FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *);static struct diff3_block *create_diff3_block (lin, lin, lin, lin, lin, lin);static struct diff3_block *make_3way_diff (struct diff_block *, struct diff_block *);static struct diff3_block *reverse_diff3_blocklist (struct diff3_block *);static struct diff3_block *using_to_diff3_block (struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *);static struct diff_block *process_diff (char const *, char const *, struct diff_block **);static void check_stdout (void);static void fatal (char const *) __attribute__((noreturn));static void output_diff3 (FILE *, struct diff3_block *, int const[3], int const[3]);static void perror_with_exit (char const *) __attribute__((noreturn));static void try_help (char const *, char const *) __attribute__((noreturn));static void usage (void);static char const *diff_program = DEFAULT_DIFF_PROGRAM;/* Values for long options that do not have single-letter equivalents.  */enum{  DIFF_PROGRAM_OPTION = CHAR_MAX + 1,  HELP_OPTION,  STRIP_TRAILING_CR_OPTION};static struct option const longopts[] ={  {"diff-program", 1, 0, DIFF_PROGRAM_OPTION},  {"easy-only", 0, 0, '3'},  {"ed", 0, 0, 'e'},  {"help", 0, 0, HELP_OPTION},  {"initial-tab", 0, 0, 'T'},  {"label", 1, 0, 'L'},  {"merge", 0, 0, 'm'},  {"overlap-only", 0, 0, 'x'},  {"show-all", 0, 0, 'A'},  {"show-overlap", 0, 0, 'E'},  {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},  {"text", 0, 0, 'a'},  {"version", 0, 0, 'v'},  {0, 0, 0, 0}};intmain (int argc, char **argv){  int c, i;  int common;  int mapping[3];  int rev_mapping[3];  int incompat = 0;  bool 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;  exit_failure = 2;  initialize_main (&argc, &argv);  program_name = argv[0];  setlocale (LC_ALL, "");  bindtextdomain (PACKAGE, LOCALEDIR);  textdomain (PACKAGE);  c_stack_action (0);  while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != -1)    {      switch (c)	{	case 'a':	  text = true;	  break;	case 'A':	  show_2nd = true;	  flagging = true;	  incompat++;	  break;	case 'x':	  overlap_only = true;	  incompat++;	  break;	case '3':	  simple_only = true;	  incompat++;	  break;	case 'i':	  finalwrite = true;	  break;	case 'm':	  merge = true;	  break;	case 'X':	  overlap_only = true;	  /* Fall through.  */	case 'E':	  flagging = true;	  /* Fall through.  */	case 'e':	  incompat++;	  break;	case 'T':	  initial_tab = true;	  break;	case STRIP_TRAILING_CR_OPTION:	  strip_trailing_cr = true;	  break;	case 'v':	  version_etc (stdout, "diff3", PACKAGE_NAME, PACKAGE_VERSION,		       "Randy Smith", (char *) 0);	  check_stdout ();	  return EXIT_SUCCESS;	case DIFF_PROGRAM_OPTION:	  diff_program = optarg;	  break;	case HELP_OPTION:	  usage ();	  check_stdout ();	  return EXIT_SUCCESS;	case 'L':	  /* Handle up to three -L options.  */	  if (tag_count < 3)	    {	      tag_strings[tag_count++] = optarg;	      break;	    }	  try_help ("too many file label options", 0);	default:	  try_help (0, 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", 0);  if (argc - optind != 3)    {      if (argc - optind < 3)	try_help ("missing operand after `%s'", argv[argc - 1]);      else	try_help ("extra operand `%s'", argv[optind + 3]);    }  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.     Also, try to compare file0 to file1, because this is where     changes are expected to come from.  Diffing between these pairs     of files is more likely to avoid phantom changes from file0 to file1.     Historically, the default common file was file2, so some older     applications (e.g. Emacs ediff) used file2 as the ancestor.  So,     for compatibility, if this is a 3-way diff (not a merge or     edscript), prefer file2 as the common file.  */  common = 2 - (edscript | merge);  if (strcmp (file[common], "-") == 0)    {      /* Sigh.  We've got standard input as the common file.  We can't	 call diff twice on stdin.  Use the other arg as the common	 file instead.  */      common = 3 - common;      if (strcmp (file[0], "-") == 0 || strcmp (file[common], "-") == 0)	fatal ("`-' specified for more than one input file");    }  mapping[0] = 0;  mapping[1] = 3 - common;  mapping[2] = common;  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))	  error (EXIT_TROUBLE, EISDIR, "%s", file[i]);      }#ifdef SIGCHLD  /* System V fork+wait does not work if SIGCHLD is ignored.  */  signal (SIGCHLD, SIG_DFL);#endif  /* Invoke diff twice on two pairs of input files, combine the two     diffs, and output them.  */  commonname = file[rev_mapping[FILEC]];  thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);  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 failed");    }  else    {      output_diff3 (stdout, diff3, mapping, rev_mapping);      conflicts_found = false;    }  check_stdout ();  exit (conflicts_found);  return conflicts_found;}static voidtry_help (char const *reason_msgid, char const *operand){  if (reason_msgid)    error (0, 0, _(reason_msgid), operand);  error (EXIT_TROUBLE, 0,	 _("Try `%s --help' for more information."), program_name);  abort ();}static voidcheck_stdout (void){  if (ferror (stdout))    fatal ("write failed");  else if (fclose (stdout) != 0)    perror_with_exit (_("standard output"));}static char const * const option_help_msgid[] = {  N_("-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_("-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_("--strip-trailing-cr  Strip trailing carriage return on input."),

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -