📄 sdiff.c
字号:
int diff_fds[2]; if (pipe (diff_fds) != 0) perror_fatal ("pipe"); diffpid = fork (); if (diffpid < 0) perror_fatal ("fork failed"); if (!diffpid) { signal (SIGINT, SIG_IGN); /* in case user interrupts editor */ signal (SIGPIPE, SIG_DFL); close (diff_fds[0]); if (diff_fds[1] != STDOUT_FILENO) { dup2 (diff_fds[1], STDOUT_FILENO); close (diff_fds[1]); } execdiff (); } close (diff_fds[1]); diffout = fdopen (diff_fds[0], "r"); if (!diffout) perror_fatal ("fdopen"); }#endif /* HAVE_FORK */ lf_init (&diff_filt, diffout); lf_init (&lfilt, left); lf_init (&rfilt, right); interact_ok = interact (&diff_filt, &lfilt, &rfilt, out); ck_fclose (left); ck_fclose (right); ck_fclose (out); { int wstatus;#if ! HAVE_FORK wstatus = pclose (diffout);#else ck_fclose (diffout); while (waitpid (diffpid, &wstatus, 0) < 0) if (errno == EINTR) checksigs (); else perror_fatal ("wait failed"); diffpid = 0;#endif if (tmpmade) { unlink (tmpname); tmpmade = 0; } if (! interact_ok) exiterr (); if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2)) fatal ("Subsidiary diff failed"); untrapsig (0); checksigs (); exit (WEXITSTATUS (wstatus)); } } return 0; /* Fool -Wall . . . */}static voiddiffarg (a) char const *a;{ static unsigned diffargs, diffargsmax; if (diffargs == diffargsmax) { if (! diffargsmax) { diffargv = (char const **) xmalloc (sizeof (char)); diffargsmax = 8; } diffargsmax *= 2; diffargv = (char const **) realloc (diffargv, diffargsmax * sizeof (char const *)); if (! diffargv) fatal ("out of memory"); } diffargv[diffargs++] = a;}static voidexecdiff (){ execvp (diffbin, (char **) diffargv); write (STDERR_FILENO, diffbin, strlen (diffbin)); write (STDERR_FILENO, ": not found\n", 12); _exit (2);}/* Signal handling */#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};/* Prefer `sigaction' if it is available, since `signal' can lose signals. */#if HAVE_SIGACTIONstatic struct sigaction initial_action[NUM_SIGS];#define initial_handler(i) (initial_action[i].sa_handler)#elsestatic RETSIGTYPE (*initial_action[NUM_SIGS]) ();#define initial_handler(i) (initial_action[i])#endifstatic int volatile ignore_SIGINT;static int volatile signal_received;static int sigs_trapped;static RETSIGTYPEcatchsig (s) int s;{#if ! HAVE_SIGACTION signal (s, SIG_IGN);#endif if (! (s == SIGINT && ignore_SIGINT)) signal_received = s;}static voidtrapsigs (){ int i;#if HAVE_SIGACTION struct sigaction catchaction; bzero (&catchaction, sizeof (catchaction)); catchaction.sa_handler = catchsig;#ifdef SA_INTERRUPT /* Non-Posix BSD-style systems like SunOS 4.1.x need this so that `read' calls are interrupted properly. */ catchaction.sa_flags = SA_INTERRUPT;#endif sigemptyset (&catchaction.sa_mask); for (i = 0; i < NUM_SIGS; i++) sigaddset (&catchaction.sa_mask, sigs[i]); for (i = 0; i < NUM_SIGS; i++) { sigaction (sigs[i], 0, &initial_action[i]); if (initial_handler (i) != SIG_IGN && sigaction (sigs[i], &catchaction, 0) != 0) fatal ("signal error"); }#else /* ! HAVE_SIGACTION */ for (i = 0; i < NUM_SIGS; i++) { initial_action[i] = signal (sigs[i], SIG_IGN); if (initial_handler (i) != SIG_IGN && signal (sigs[i], catchsig) != SIG_IGN) fatal ("signal error"); }#endif /* ! HAVE_SIGACTION */#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 sigs_trapped = 1;}/* Untrap signal S, or all trapped signals if S is zero. */static voiduntrapsig (s) int s;{ int i; if (sigs_trapped) for (i = 0; i < NUM_SIGS; i++) if ((!s || sigs[i] == s) && initial_handler (i) != SIG_IGN)#if HAVE_SIGACTION sigaction (sigs[i], &initial_action[i], 0);#else signal (sigs[i], initial_action[i]);#endif}/* Exit if a signal has been received. */static voidchecksigs (){ int s = signal_received; if (s) { cleanup (); /* Yield an exit status indicating that a signal was received. */ untrapsig (s); kill (getpid (), s); /* That didn't work, so exit with error status. */ exit (2); }}static voidgive_help (){ fprintf (stderr,"l:\tuse the left version\n"); fprintf (stderr,"r:\tuse the right version\n"); fprintf (stderr,"e l:\tedit then use the left version\n"); fprintf (stderr,"e r:\tedit then use the right version\n"); fprintf (stderr,"e b:\tedit then use the left and right versions concatenated\n"); fprintf (stderr,"e:\tedit a new version\n"); fprintf (stderr,"s:\tsilently include common lines\n"); fprintf (stderr,"v:\tverbosely include common lines\n"); fprintf (stderr,"q:\tquit\n");}static intskip_white (){ int c; for (;;) { c = getchar (); if (!ISSPACE (c) || c == '\n') break; checksigs (); } if (ferror (stdin)) perror_fatal ("input error"); return c;}static voidflush_line (){ int c; while ((c = getchar ()) != '\n' && c != EOF) ; if (ferror (stdin)) perror_fatal ("input error");}/* interpret an edit command */static intedit (left, lenl, right, lenr, outfile) struct line_filter *left; int lenl; struct line_filter *right; int lenr; FILE *outfile;{ for (;;) { int cmd0, cmd1; int gotcmd = 0; cmd1 = 0; /* Pacify `gcc -W'. */ while (!gotcmd) { if (putchar ('%') != '%') perror_fatal ("output error"); ck_fflush (stdout); cmd0 = skip_white (); switch (cmd0) { case 'l': case 'r': case 's': case 'v': case 'q': if (skip_white () != '\n') { give_help (); flush_line (); continue; } gotcmd = 1; break; case 'e': cmd1 = skip_white (); switch (cmd1) { case 'l': case 'r': case 'b': if (skip_white () != '\n') { give_help (); flush_line (); continue; } gotcmd = 1; break; case '\n': gotcmd = 1; break; default: give_help (); flush_line (); continue; } break; case EOF: if (feof (stdin)) { gotcmd = 1; cmd0 = 'q'; break; } /* falls through */ default: flush_line (); /* falls through */ case '\n': give_help (); continue; } } switch (cmd0) { case 'l': lf_copy (left, lenl, outfile); lf_skip (right, lenr); return 1; case 'r': lf_copy (right, lenr, outfile); lf_skip (left, lenl); return 1; case 's': suppress_common_flag = 1; break; case 'v': suppress_common_flag = 0; break; case 'q': return 0; case 'e': { int tfd; FILE *tmp; if (tmpmade) { unlink (tmpname); tmpmade = 0; free (tmpname); } asprintf (&tmpname, "%s/sdiff.XXXXXX", getenv("TMPDIR") ?: P_tmpdir); if (tmpname == NULL) perror_fatal ("temporary file name"); tfd = mkstemp(tmpname); if (tfd == -1) perror_fatal ("temporary file name"); tmp = fdopen (tfd, "w+"); if (tmp == NULL) perror_fatal ("temporary file name"); tmpmade = 1; if (cmd1 == 'l' || cmd1 == 'b') lf_copy (left, lenl, tmp); else lf_skip (left, lenl); if (cmd1 == 'r' || cmd1 == 'b') lf_copy (right, lenr, tmp); else lf_skip (right, lenr); ck_fflush (tmp); { int wstatus;#if ! HAVE_FORK char *command = xmalloc (strlen (edbin) + strlen (tmpname) + 2); sprintf (command, "%s %s", edbin, tmpname); wstatus = system (command); free (command);#else /* HAVE_FORK */ pid_t pid; ignore_SIGINT = 1; checksigs (); pid = fork (); if (pid == 0) { char const *argv[3]; int i = 0; argv[i++] = edbin; argv[i++] = tmpname; argv[i++] = 0; execvp (edbin, (char **) argv); write (STDERR_FILENO, edbin, strlen (edbin)); write (STDERR_FILENO, ": not found\n", 12); _exit (1); } if (pid < 0) perror_fatal ("fork failed"); while (waitpid (pid, &wstatus, 0) < 0) if (errno == EINTR) checksigs (); else perror_fatal ("wait failed"); ignore_SIGINT = 0;#endif /* HAVE_FORK */ if (wstatus != 0) fatal ("Subsidiary editor failed"); } if (fseek (tmp, 0L, SEEK_SET) != 0) perror_fatal ("fseek"); { /* SDIFF_BUFSIZE is too big for a local var in some compilers, so we allocate it dynamically. */ char *buf = xmalloc (SDIFF_BUFSIZE); size_t size; while ((size = ck_fread (buf, SDIFF_BUFSIZE, tmp)) != 0) { checksigs (); ck_fwrite (buf, size, outfile); } ck_fclose (tmp); free (buf); } return 1; } default: give_help (); break; } }}/* Alternately reveal bursts of diff output and handle user commands. */static intinteract (diff, left, right, outfile) struct line_filter *diff; struct line_filter *left; struct line_filter *right; FILE *outfile;{ for (;;) { char diff_help[256]; int snarfed = lf_snarf (diff, diff_help, sizeof (diff_help)); if (snarfed <= 0) return snarfed; checksigs (); switch (diff_help[0]) { case ' ': puts (diff_help + 1); break; case 'i': { int lenl = atoi (diff_help + 1), lenr, lenmax; char *p = strchr (diff_help, ','); if (!p) fatal (diff_help); lenr = atoi (p + 1); lenmax = max (lenl, lenr); if (suppress_common_flag) lf_skip (diff, lenmax); else lf_copy (diff, lenmax, stdout); lf_copy (left, lenl, outfile); lf_skip (right, lenr); break; } case 'c': { int lenl = atoi (diff_help + 1), lenr; char *p = strchr (diff_help, ','); if (!p) fatal (diff_help); lenr = atoi (p + 1); lf_copy (diff, max (lenl, lenr), stdout); if (! edit (left, lenl, right, lenr, outfile)) return 0; break; } default: fatal (diff_help); break; } }}/* temporary lossage: this is torn from gnu libc *//* Return nonzero if DIR is an existing directory. */static intdiraccess (dir) char const *dir;{ struct stat buf; return stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -