📄 sdiff.c
字号:
/* 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"#endifextern 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;#endifstruct 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"); diffarg ("--"); diffarg (argv[optind]); diffarg (argv[optind + 1]); diffarg (0); execdiff (); } else { FILE *left, *right, *out, *diffout; int interact_ok; struct line_filter lfilt; struct line_filter rfilt; struct line_filter diff_filt; int leftdir = diraccess (argv[optind]); int rightdir = diraccess (argv[optind + 1]); if (leftdir && rightdir) fatal ("both files to be compared are directories"); left = ck_fopen (expand_name (argv[optind], leftdir, argv[optind + 1]), "r"); ; right = ck_fopen (expand_name (argv[optind + 1], rightdir, argv[optind]), "r"); out = ck_fopen (out_file, "w"); diffarg ("--sdiff-merge-assist"); diffarg ("--"); diffarg (argv[optind]); diffarg (argv[optind + 1]); diffarg (0); trapsigs ();#if ! HAVE_FORK { size_t cmdsize = 1; char *p, *command; int i; for (i = 0; diffargv[i]; i++) cmdsize += 4 * strlen (diffargv[i]) + 3; command = p = xmalloc (cmdsize); for (i = 0; diffargv[i]; i++) { char const *a = diffargv[i]; SYSTEM_QUOTE_ARG (p, a); *p++ = ' '; } p[-1] = '\0'; diffout = popen (command, "r"); if (!diffout) perror_fatal (command); free (command); }#else /* HAVE_FORK */ {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -