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

📄 sdiff.c

📁 制作2.6内核的CLFS时 使用的diffutils-2.8.7.tar.gz包
💻 C
📖 第 1 页 / 共 2 页
字号:
/* sdiff - side-by-side merge of file differences   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 2001, 2002, 2004   Free Software Foundation, Inc.   This file is part of GNU DIFF.   GNU DIFF 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.   GNU DIFF 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 <dirname.h>#include <error.h>#include <exit.h>#include <exitfail.h>#include <file-type.h>#include <getopt.h>#include <quotesys.h>#include <version-etc.h>#include <xalloc.h>/* Size of chunks read from files which must be parsed into lines.  */#define SDIFF_BUFSIZE ((size_t) 65536)char *program_name;static char const *editor_program = DEFAULT_EDITOR_PROGRAM;static char const **diffargv;static char * volatile tmpname;static FILE *tmp;#if HAVE_WORKING_FORK || HAVE_WORKING_VFORKstatic pid_t volatile diffpid;#endifstruct line_filter;static void catchsig (int);static bool edit (struct line_filter *, char const *, lin, lin, struct line_filter *, char const *, lin, lin, FILE *);static bool interact (struct line_filter *, struct line_filter *, char const *, struct line_filter *, char const *, FILE *);static void checksigs (void);static void diffarg (char const *);static void fatal (char const *) __attribute__((noreturn));static void perror_fatal (char const *) __attribute__((noreturn));static void trapsigs (void);static void untrapsig (int);#define NUM_SIGS (sizeof sigs / sizeof *sigs)static int const sigs[] = {#ifdef SIGHUP       SIGHUP,#endif#ifdef SIGQUIT       SIGQUIT,#endif#ifdef SIGTERM       SIGTERM,#endif#ifdef SIGXCPU       SIGXCPU,#endif#ifdef SIGXFSZ       SIGXFSZ,#endif       SIGINT,       SIGPIPE};#define handler_index_of_SIGINT (NUM_SIGS - 2)#define handler_index_of_SIGPIPE (NUM_SIGS - 1)#if HAVE_SIGACTION  /* Prefer `sigaction' if available, since `signal' can lose signals.  */  static struct sigaction initial_action[NUM_SIGS];# define initial_handler(i) (initial_action[i].sa_handler)  static void signal_handler (int, void (*) (int));#else  static void (*initial_action[NUM_SIGS]) ();# define initial_handler(i) (initial_action[i])# define signal_handler(sig, handler) signal (sig, handler)#endif#if ! HAVE_SIGPROCMASK# define sigset_t int# define sigemptyset(s) (*(s) = 0)# ifndef sigmask#  define sigmask(sig) (1 << ((sig) - 1))# endif# define sigaddset(s, sig) (*(s) |= sigmask (sig))# ifndef SIG_BLOCK#  define SIG_BLOCK 0# endif# ifndef SIG_SETMASK#  define SIG_SETMASK (! SIG_BLOCK)# endif# define sigprocmask(how, n, o) \    ((how) == SIG_BLOCK ? *(o) = sigblock (*(n)) : sigsetmask (*(n)))#endifstatic bool diraccess (char const *);static int temporary_file (void);/* Options: *//* Name of output file if -o specified.  */static char const *output;/* Do not print common lines.  */static bool suppress_common_lines;/* Value for the long option that does not have single-letter equivalents.  */enum{  DIFF_PROGRAM_OPTION = CHAR_MAX + 1,  HELP_OPTION,  STRIP_TRAILING_CR_OPTION,  TABSIZE_OPTION};static struct option const longopts[] ={  {"diff-program", 1, 0, DIFF_PROGRAM_OPTION},  {"expand-tabs", 0, 0, 't'},  {"help", 0, 0, HELP_OPTION},  {"ignore-all-space", 0, 0, 'W'}, /* swap W and w for historical reasons */  {"ignore-blank-lines", 0, 0, 'B'},  {"ignore-case", 0, 0, 'i'},  {"ignore-matching-lines", 1, 0, 'I'},  {"ignore-space-change", 0, 0, 'b'},  {"ignore-tab-expansion", 0, 0, 'E'},  {"left-column", 0, 0, 'l'},  {"minimal", 0, 0, 'd'},  {"output", 1, 0, 'o'},  {"speed-large-files", 0, 0, 'H'},  {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},  {"suppress-common-lines", 0, 0, 's'},  {"tabsize", 1, 0, TABSIZE_OPTION},  {"text", 0, 0, 'a'},  {"version", 0, 0, 'v'},  {"width", 1, 0, 'w'},  {0, 0, 0, 0}};static void try_help (char const *, char const *) __attribute__((noreturn));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_fatal (_("standard output"));}static char const * const option_help_msgid[] = {  N_("-o FILE  --output=FILE  Operate interactively, sending output to FILE."),  "",  N_("-i  --ignore-case  Consider upper- and lower-case to be the same."),  N_("-E  --ignore-tab-expansion  Ignore changes due to tab expansion."),  N_("-b  --ignore-space-change  Ignore changes in the amount of white space."),  N_("-W  --ignore-all-space  Ignore all white space."),  N_("-B  --ignore-blank-lines  Ignore changes whose lines are all blank."),  N_("-I RE  --ignore-matching-lines=RE  Ignore changes whose lines all match RE."),  N_("--strip-trailing-cr  Strip trailing carriage return on input."),  N_("-a  --text  Treat all files as text."),  "",  N_("-w NUM  --width=NUM  Output at most NUM (default 130) print columns."),  N_("-l  --left-column  Output only the left column of common lines."),  N_("-s  --suppress-common-lines  Do not output common lines."),  "",  N_("-t  --expand-tabs  Expand tabs to spaces in output."),  N_("--tabsize=NUM  Tab stops are every NUM (default 8) print columns."),  "",  N_("-d  --minimal  Try hard to find a smaller set of changes."),  N_("-H  --speed-large-files  Assume large files and many scattered small changes."),  N_("--diff-program=PROGRAM  Use PROGRAM to compare files."),  "",  N_("-v  --version  Output version info."),  N_("--help  Output this help."),  0};static voidusage (void){  char const * const *p;  printf (_("Usage: %s [OPTION]... FILE1 FILE2\n"), program_name);  printf ("%s\n\n", _("Side-by-side merge of file differences."));  for (p = option_help_msgid;  *p;  p++)    if (**p)      printf ("  %s\n", _(*p));    else      putchar ('\n');  printf ("\n%s\n%s\n\n%s\n",	  _("If a FILE is `-', read standard input."),	  _("Exit status is 0 if inputs are the same, 1 if different, 2 if trouble."),	  _("Report bugs to <bug-gnu-utils@gnu.org>."));}/* Clean up after a signal or other failure.  This function is   async-signal-safe.  */static voidcleanup (int signo __attribute__((unused))){#if HAVE_WORKING_FORK || HAVE_WORKING_VFORK  if (0 < diffpid)    kill (diffpid, SIGPIPE);#endif  if (tmpname)    unlink (tmpname);}static void exiterr (void) __attribute__((noreturn));static voidexiterr (void){  cleanup (0);  untrapsig (0);  checksigs ();  exit (EXIT_TROUBLE);}static voidfatal (char const *msgid){  error (0, 0, "%s", _(msgid));  exiterr ();}static voidperror_fatal (char const *msg){  int e = errno;  checksigs ();  error (0, e, "%s", msg);  exiterr ();}static voidcheck_child_status (int werrno, int wstatus, int max_ok_status,		    char const *subsidiary_program){  int status = (! werrno && WIFEXITED (wstatus)		? WEXITSTATUS (wstatus)		: INT_MAX);  if (max_ok_status < status)    {      error (0, werrno,	     _(status == 126	       ? "subsidiary program `%s' could not be invoked"	       : status == 127	       ? "subsidiary program `%s' not found"	       : status == INT_MAX	       ? "subsidiary program `%s' failed"	       : "subsidiary program `%s' failed (exit status %d)"),	     subsidiary_program, status);      exiterr ();    }}static FILE *ck_fopen (char const *fname, char const *type){  FILE *r = fopen (fname, type);  if (! r)    perror_fatal (fname);  return r;}static voidck_fclose (FILE *f){  if (fclose (f))    perror_fatal ("fclose");}static size_tck_fread (char *buf, size_t size, FILE *f){  size_t r = fread (buf, sizeof (char), size, f);  if (r == 0 && ferror (f))    perror_fatal (_("read failed"));  return r;}static voidck_fwrite (char const *buf, size_t size, FILE *f){  if (fwrite (buf, sizeof (char), size, f) != size)    perror_fatal (_("write failed"));}static voidck_fflush (FILE *f){  if (fflush (f) != 0)    perror_fatal (_("write failed"));}static char const *expand_name (char *name, bool is_dir, char const *other_name){  if (strcmp (name, "-") == 0)    fatal ("cannot interactively merge standard input");  if (! is_dir)    return name;  else    {      /* Yield NAME/BASE, where BASE is OTHER_NAME's basename.  */      char const *base = base_name (other_name);      size_t namelen = strlen (name), baselen = strlen (base);      bool insert_slash = *base_name (name) && name[namelen - 1] != '/';      char *r = xmalloc (namelen + insert_slash + baselen + 1);      memcpy (r, name, namelen);      r[namelen] = '/';      memcpy (r + namelen + insert_slash, base, baselen + 1);      return r;    }}struct line_filter {  FILE *infile;  char *bufpos;  char *buffer;  char *buflim;};static voidlf_init (struct line_filter *lf, FILE *infile){  lf->infile = infile;  lf->bufpos = lf->buffer = lf->buflim = xmalloc (SDIFF_BUFSIZE + 1);  lf->buflim[0] = '\n';}/* Fill an exhausted line_filter buffer from its INFILE */static size_tlf_refill (struct line_filter *lf){  size_t s = ck_fread (lf->buffer, SDIFF_BUFSIZE, lf->infile);  lf->bufpos = lf->buffer;  lf->buflim = lf->buffer + s;  lf->buflim[0] = '\n';  checksigs ();  return s;}/* Advance LINES on LF's infile, copying lines to OUTFILE */static voidlf_copy (struct line_filter *lf, lin lines, FILE *outfile){  char *start = lf->bufpos;  while (lines)    {      lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);      if (! lf->bufpos)	{	  ck_fwrite (start, lf->buflim - start, outfile);	  if (! lf_refill (lf))	    return;	  start = lf->bufpos;	}      else	{	  --lines;	  ++lf->bufpos;	}    }  ck_fwrite (start, lf->bufpos - start, outfile);}/* Advance LINES on LF's infile without doing output */static voidlf_skip (struct line_filter *lf, lin lines){  while (lines)    {      lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);      if (! lf->bufpos)	{	  if (! lf_refill (lf))	    break;	}      else	{	  --lines;	  ++lf->bufpos;	}    }}/* Snarf a line into a buffer.  Return EOF if EOF, 0 if error, 1 if OK.  */static intlf_snarf (struct line_filter *lf, char *buffer, size_t bufsize){  for (;;)    {      char *start = lf->bufpos;      char *next = (char *) memchr (start, '\n', lf->buflim + 1 - start);      size_t s = next - start;      if (bufsize <= s)	return 0;      memcpy (buffer, start, s);      if (next < lf->buflim)	{	  buffer[s] = 0;	  lf->bufpos = next + 1;	  return 1;	}      if (! lf_refill (lf))	return s ? 0 : EOF;      buffer += s;      bufsize -= s;    }}intmain (int argc, char *argv[]){  int opt;  char const *prog;  exit_failure = EXIT_TROUBLE;  initialize_main (&argc, &argv);  program_name = argv[0];  setlocale (LC_ALL, "");  bindtextdomain (PACKAGE, LOCALEDIR);  textdomain (PACKAGE);  c_stack_action (cleanup);  prog = getenv ("EDITOR");  if (prog)    editor_program = prog;  diffarg (DEFAULT_DIFF_PROGRAM);  /* parse command line args */  while ((opt = getopt_long (argc, argv, "abBdEHiI:lo:stvw:W", longopts, 0))	 != -1)    {      switch (opt)	{	case 'a':	  diffarg ("-a");	  break;	case 'b':	  diffarg ("-b");	  break;	case 'B':	  diffarg ("-B");	  break;	case 'd':	  diffarg ("-d");	  break;	case 'E':	  diffarg ("-E");	  break;	case 'H':	  diffarg ("-H");	  break;	case 'i':	  diffarg ("-i");	  break;	case 'I':	  diffarg ("-I");	  diffarg (optarg);	  break;	case 'l':	  diffarg ("--left-column");	  break;	case 'o':	  output = optarg;	  break;	case 's':	  suppress_common_lines = true;	  break;	case 't':	  diffarg ("-t");	  break;	case 'v':	  version_etc (stdout, "sdiff", PACKAGE_NAME, PACKAGE_VERSION,		       "Thomas Lord", (char *) 0);	  check_stdout ();	  return EXIT_SUCCESS;	case 'w':	  diffarg ("-W");	  diffarg (optarg);	  break;	case 'W':	  diffarg ("-w");	  break;	case DIFF_PROGRAM_OPTION:	  diffargv[0] = optarg;	  break;	case HELP_OPTION:	  usage ();	  check_stdout ();	  return EXIT_SUCCESS;	case STRIP_TRAILING_CR_OPTION:	  diffarg ("--strip-trailing-cr");	  break;	case TABSIZE_OPTION:	  diffarg ("--tabsize");	  diffarg (optarg);	  break;	default:	  try_help (0, 0);	}    }  if (argc - optind != 2)    {      if (argc - optind < 2)	try_help ("missing operand after `%s'", argv[argc - 1]);      else	try_help ("extra operand `%s'", argv[optind + 2]);    }  if (! output)    {      /* easy case: diff does everything for us */      if (suppress_common_lines)	diffarg ("--suppress-common-lines");      diffarg ("-y");      diffarg ("--");      diffarg (argv[optind]);      diffarg (argv[optind + 1]);      diffarg (0);      execvp (diffargv[0], (char **) diffargv);      perror_fatal (diffargv[0]);    }  else    {      char const *lname, *rname;      FILE *left, *right, *out, *diffout;      bool interact_ok;      struct line_filter lfilt;      struct line_filter rfilt;      struct line_filter diff_filt;      bool leftdir = diraccess (argv[optind]);      bool rightdir = diraccess (argv[optind + 1]);      if (leftdir & rightdir)	fatal ("both files to be compared are directories");      lname = expand_name (argv[optind], leftdir, argv[optind + 1]);      left = ck_fopen (lname, "r");      rname = expand_name (argv[optind + 1], rightdir, argv[optind]);      right = ck_fopen (rname, "r");      out = ck_fopen (output, "w");      diffarg ("--sdiff-merge-assist");      diffarg ("--");      diffarg (argv[optind]);      diffarg (argv[optind + 1]);      diffarg (0);      trapsigs ();#if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)      {	size_t cmdsize = 1;	char *p, *command;

⌨️ 快捷键说明

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