1109 lines · 22.9 KB · C
RawDownload
/* SDIFF -- interactive merge front end to diff   Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. This file is part of GNU DIFF. GNU DIFF is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details. You should have received a copy of the GNU General Public Licensealong with GNU DIFF; see the file COPYING.  If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */ /* GNU SDIFF was written by Thomas Lord. */#include <sys/cdefs.h>__FBSDID("$FreeBSD: src/contrib/diff/sdiff.c,v 1.1.1.1.12.1 2002/01/28 01:26:35 nectar Exp $"); #include "system.h"#include <stdio.h>#include <signal.h>#include "getopt.h" /* Size of chunks read from files which must be parsed into lines. */#define SDIFF_BUFSIZE ((size_t) 65536) /* Default name of the diff program */#ifndef DIFF_PROGRAM#define DIFF_PROGRAM "/usr/bin/diff"#endif /* Users' editor of nonchoice */#ifndef DEFAULT_EDITOR_PROGRAM#define DEFAULT_EDITOR_PROGRAM "ed"#endif extern char version_string[];static char const *program_name;static char const *diffbin = DIFF_PROGRAM;static char const *edbin = DEFAULT_EDITOR_PROGRAM;static char const **diffargv; static char *tmpname;static int volatile tmpmade; #if HAVE_FORKstatic pid_t volatile diffpid;#endif struct line_filter; static FILE *ck_fopen PARAMS((char const *, char const *));static RETSIGTYPE catchsig PARAMS((int));static VOID *xmalloc PARAMS((size_t));static char const *expand_name PARAMS((char *, int, char const *));static int edit PARAMS((struct line_filter *, int, struct line_filter *, int, FILE*));static int interact PARAMS((struct line_filter *, struct line_filter *, struct line_filter *, FILE*));static int lf_snarf PARAMS((struct line_filter *, char *, size_t));static int skip_white PARAMS((void));static size_t ck_fread PARAMS((char *, size_t, FILE *));static size_t lf_refill PARAMS((struct line_filter *));static void checksigs PARAMS((void));static void ck_fclose PARAMS((FILE *));static void ck_fflush PARAMS((FILE *));static void ck_fwrite PARAMS((char const *, size_t, FILE *));static void cleanup PARAMS((void));static void diffarg PARAMS((char const *));static void execdiff PARAMS((void));static void exiterr PARAMS((void));static void fatal PARAMS((char const *));static void flush_line PARAMS((void));static void give_help PARAMS((void));static void lf_copy PARAMS((struct line_filter *, int, FILE *));static void lf_init PARAMS((struct line_filter *, FILE *));static void lf_skip PARAMS((struct line_filter *, int));static void perror_fatal PARAMS((char const *));static void trapsigs PARAMS((void));static void try_help PARAMS((char const *));static void untrapsig PARAMS((int));static void usage PARAMS((void)); static int diraccess PARAMS((char const *)); /* Options: */ /* name of output file if -o spec'd */static char *out_file; /* do not print common lines if true, set by -s option */static int suppress_common_flag; static struct option const longopts[] ={  {"ignore-blank-lines", 0, 0, 'B'},  {"speed-large-files", 0, 0, 'H'},  {"ignore-matching-lines", 1, 0, 'I'},  {"ignore-all-space", 0, 0, 'W'}, /* swap W and w for historical reasons */  {"text", 0, 0, 'a'},  {"ignore-space-change", 0, 0, 'b'},  {"minimal", 0, 0, 'd'},  {"ignore-case", 0, 0, 'i'},  {"left-column", 0, 0, 'l'},  {"output", 1, 0, 'o'},  {"suppress-common-lines", 0, 0, 's'},  {"expand-tabs", 0, 0, 't'},  {"width", 1, 0, 'w'},  {"version", 0, 0, 'v'},  {"help", 0, 0, 129},  {0, 0, 0, 0}}; 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 voidusage (){  printf ("Usage: %s [OPTIONS]... FILE1 FILE2\n\n", program_name);  printf ("%s", "\  -o FILE  --output=FILE  Operate interactively, sending output to FILE.\n\n");  printf ("%s", "\  -i  --ignore-case  Consider upper- and lower-case to be the same.\n\  -W  --ignore-all-space  Ignore all white space.\n\  -b  --ignore-space-change  Ignore changes in the amount of 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\  -a  --text  Treat all files as text.\n\n");  printf ("%s", "\  -w NUM  --width=NUM  Output at most NUM (default 130) characters per line.\n\  -l  --left-column  Output only the left column of common lines.\n\  -s  --suppress-common-lines  Do not output common lines.\n\n");  printf ("\  -t  --expand-tabs  Expand tabs to spaces in output.\n\n");  printf ("%s", "\  -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\n"); printf ("%s", "\  -v  --version  Output version info.\n\  --help  Output this help.\n\n\If FILE1 or FILE2 is `-', read standard input.\n");} static voidcleanup (){#if HAVE_FORK  if (0 < diffpid)    kill (diffpid, SIGPIPE);#endif  if (tmpmade)    unlink (tmpname);} static voidexiterr (){  cleanup ();  untrapsig (0);  checksigs ();  exit (2);} static voidfatal (msg)     char const *msg;{  fprintf (stderr, "%s: %s\n", program_name, msg);  exiterr ();} static voidperror_fatal (msg)     char const *msg;{  int e = errno;  checksigs ();  fprintf (stderr, "%s: ", program_name);  errno = e;  perror (msg);  exiterr ();}  /* malloc freely or DIE! */static VOID *xmalloc (size)     size_t size;{  VOID *r = (VOID *) malloc (size);  if (!r)    fatal ("memory exhausted");  return r;} static FILE *ck_fopen (fname, type)     char const *fname, *type;{  FILE *r = fopen (fname, type);  if (!r)    perror_fatal (fname);  return r;} static voidck_fclose (f)     FILE *f;{  if (fclose (f))    perror_fatal ("input/output error");} static size_tck_fread (buf, size, f)     char *buf;     size_t size;     FILE *f;{  size_t r = fread (buf, sizeof (char), size, f);  if (r == 0 && ferror (f))    perror_fatal ("input error");  return r;} static voidck_fwrite (buf, size, f)     char const *buf;     size_t size;     FILE *f;{  if (fwrite (buf, sizeof (char), size, f) != size)    perror_fatal ("output error");} static voidck_fflush (f)     FILE *f;{  if (fflush (f) != 0)    perror_fatal ("output error");} static char const *expand_name (name, is_dir, other_name)     char *name;     int 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 *p = filename_lastdirchar (other_name);      char const *base = p ? p+1 : other_name;      size_t namelen = strlen (name), baselen = strlen (base);      char *r = xmalloc (namelen + baselen + 2);      memcpy (r, name, namelen);      r[namelen] = '/';      memcpy (r + namelen + 1, base, baselen + 1);      return r;    }}  struct line_filter {  FILE *infile;  char *bufpos;  char *buffer;  char *buflim;}; static voidlf_init (lf, infile)     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 (lf)     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 (lf, lines, outfile)     struct line_filter *lf;     int 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 (lf, lines)     struct line_filter *lf;     int 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 (lf, buffer, bufsize)     struct line_filter *lf;     char *buffer;     size_t bufsize;{  char *start = lf->bufpos;   for (;;)    {      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;      start = next;    }}  intmain (argc, argv)     int argc;     char *argv[];{  int opt;  char *editor;  char *differ;   initialize_main (&argc, &argv);  program_name = argv[0];   editor = getenv ("EDITOR");  if (editor)    edbin = editor;  differ = getenv ("DIFF");  if (differ)    diffbin = differ;   diffarg ("diff");   /* parse command line args */  while ((opt = getopt_long (argc, argv, "abBdHiI:lo:stvw:W", longopts, 0))	 != EOF)    {      switch (opt)	{	case 'a':	  diffarg ("-a");	  break; 	case 'b':	  diffarg ("-b");	  break; 	case 'B':	  diffarg ("-B");	  break; 	case 'd':	  diffarg ("-d");	  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':	  out_file = optarg;	  break; 	case 's':	  suppress_common_flag = 1;	  break; 	case 't':	  diffarg ("-t");	  break; 	case 'v':	  printf ("sdiff - GNU diffutils version %s\n", version_string);	  exit (0); 	case 'w':	  diffarg ("-W");	  diffarg (optarg);	  break; 	case 'W':	  diffarg ("-w");	  break; 	case 129:	  usage ();	  if (ferror (stdout) || fclose (stdout) != 0)	    fatal ("write error");	  exit (0); 	default:	  try_help (0);	}    }   if (argc - optind != 2)    try_help (argc - optind < 2 ? "missing operand" : "extra operand");   if (! out_file)    {      /* easy case: diff does everything for us */      if (suppress_common_flag)	diffarg ("--suppress-common-lines");      diffarg ("-y");

Lines 1–500 of 1109.