Only in .: .depend Only in .: .depend.common.o Only in .: .depend.decompress.o Only in .: .depend.edit.o Only in .: .depend.sdiff.o Only in .: .sdiff.c.un~ diff -ru /home/bapt/dev/NetBSD/src/usr.bin/sdiff/common.c ./common.c --- /home/bapt/dev/NetBSD/src/usr.bin/sdiff/common.c 2007-02-18 23:13:42.000000000 +0100 +++ ./common.c 2016-04-17 00:26:26.432779000 +0200 @@ -1,4 +1,3 @@ -/* $NetBSD: common.c,v 1.1 2007/02/18 22:13:42 rmind Exp $ */ /* $OpenBSD: common.c,v 1.4 2006/05/25 03:20:32 ray Exp $ */ /* @@ -6,6 +5,9 @@ * Public domain. */ +#include +__FBSDID("$FreeBSD$"); + #include #include #include @@ -15,7 +17,8 @@ void cleanup(const char *filename) { + if (unlink(filename)) err(2, "could not delete: %s", filename); - exit(2); + exit(1); } diff -ru /home/bapt/dev/NetBSD/src/usr.bin/sdiff/common.h ./common.h --- /home/bapt/dev/NetBSD/src/usr.bin/sdiff/common.h 2015-01-29 04:28:19.000000000 +0100 +++ ./common.h 2016-04-16 22:11:15.815783000 +0200 @@ -1,4 +1,3 @@ -/* $NetBSD: common.h,v 1.2 2015/01/29 03:28:19 christos Exp $ */ /* $OpenBSD: common.h,v 1.2 2006/05/25 03:20:32 ray Exp $ */ /* @@ -6,4 +5,4 @@ * Public domain. */ -__dead void cleanup(const char *); +void cleanup(const char *) __dead2; Only in .: common.o Only in /home/bapt/dev/NetBSD/src/usr.bin/sdiff: CVS diff -ru /home/bapt/dev/NetBSD/src/usr.bin/sdiff/edit.c ./edit.c --- /home/bapt/dev/NetBSD/src/usr.bin/sdiff/edit.c 2011-09-01 09:18:51.000000000 +0200 +++ ./edit.c 2016-04-16 22:32:17.819172000 +0200 @@ -1,16 +1,21 @@ -/* $NetBSD: edit.c,v 1.4 2011/09/01 07:18:51 plunky Exp $ */ -/* $OpenBSD: edit.c,v 1.14 2006/05/25 03:20:32 ray Exp $ */ +/* $OpenBSD: edit.c,v 1.19 2009/06/07 13:29:50 ray Exp $ */ /* * Written by Raymond Lai . * Public domain. */ +#include +__FBSDID("$FreeBSD$"); + #include #include #include #include +#include +#include +#include #include #include #include @@ -19,48 +24,58 @@ #include "common.h" #include "extern.h" -static void edit(const char *); +int editit(const char *); /* - * Takes the name of a file and opens it with an editor. + * Execute an editor on the specified pathname, which is interpreted + * from the shell. This means flags may be included. + * + * Returns -1 on error, or the exit value on success. */ -static void -edit(const char *filename) +int +editit(const char *pathname) { - int status; + char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p; + sig_t sighup, sigint, sigquit, sigchld; pid_t pid; - const char *editor; + int saved_errno, st, ret = -1; - editor = getenv("VISUAL"); - if (editor == NULL) - editor = getenv("EDITOR"); - if (editor == NULL) - editor = "vi"; - - /* Start editor on temporary file. */ - switch (pid = fork()) { - case 0: - /* child */ - execlp(editor, editor, filename, (void *)NULL); - warn("could not execute editor: %s", editor); - cleanup(filename); - case -1: - warn("could not fork"); - cleanup(filename); - } - - /* parent */ - /* Wait for editor to exit. */ - if (waitpid(pid, &status, 0) == -1) { - warn("waitpid"); - cleanup(filename); - } + ed = getenv("VISUAL"); + if (ed == NULL || ed[0] == '\0') + ed = getenv("EDITOR"); + if (ed == NULL || ed[0] == '\0') + ed = _PATH_VI; + if (asprintf(&p, "%s %s", ed, pathname) == -1) + return (-1); + argp[2] = p; - /* Check that editor terminated normally. */ - if (!WIFEXITED(status)) { - warn("%s terminated abnormally", editor); - cleanup(filename); - } + sighup = signal(SIGHUP, SIG_IGN); + sigint = signal(SIGINT, SIG_IGN); + sigquit = signal(SIGQUIT, SIG_IGN); + sigchld = signal(SIGCHLD, SIG_DFL); + if ((pid = fork()) == -1) + goto fail; + if (pid == 0) { + execv(_PATH_BSHELL, argp); + _exit(127); + } + while (waitpid(pid, &st, 0) == -1) + if (errno != EINTR) + goto fail; + if (!WIFEXITED(st)) + errno = EINTR; + else + ret = WEXITSTATUS(st); + + fail: + saved_errno = errno; + (void)signal(SIGHUP, sighup); + (void)signal(SIGINT, sigint); + (void)signal(SIGQUIT, sigquit); + (void)signal(SIGCHLD, sigchld); + free(p); + errno = saved_errno; + return (ret); } /* @@ -70,13 +85,13 @@ eparse(const char *cmd, const char *left, const char *right) { FILE *file; - size_t nread, nwritten; + size_t nread; int fd; char *filename; char buf[BUFSIZ], *text; /* Skip whitespace. */ - while (isspace((int)(*cmd))) + while (isspace(*cmd)) ++cmd; text = NULL; @@ -130,9 +145,11 @@ err(2, "mkstemp"); if (text != NULL) { size_t len; + ssize_t nwritten; len = strlen(text); - if ((size_t)write(fd, text, len) != len) { + if ((nwritten = write(fd, text, len)) == -1 || + (size_t)nwritten != len) { warn("error writing to temp file"); cleanup(filename); } @@ -143,7 +160,10 @@ free(text); /* Edit temp file. */ - edit(filename); + if (editit(filename) == -1) { + warn("error editing %s", filename); + cleanup(filename); + } /* Open temporary file. */ if (!(file = fopen(filename, "r"))) { @@ -153,6 +173,8 @@ /* Copy temporary file contents to output file. */ for (nread = sizeof(buf); nread == sizeof(buf);) { + size_t nwritten; + nread = fread(buf, sizeof(*buf), sizeof(buf), file); /* Test for error or end of file. */ if (nread != sizeof(buf) && @@ -169,7 +191,7 @@ break; /* Write data we just read. */ - nwritten = fwrite(buf, sizeof(*buf), nread, outfile); + nwritten = fwrite(buf, sizeof(*buf), nread, outfp); if (nwritten != nread) { warnx("error writing to output file"); cleanup(filename); Only in .: edit.o diff -ru /home/bapt/dev/NetBSD/src/usr.bin/sdiff/extern.h ./extern.h --- /home/bapt/dev/NetBSD/src/usr.bin/sdiff/extern.h 2007-02-18 23:13:42.000000000 +0100 +++ ./extern.h 2016-04-16 22:11:15.663004000 +0200 @@ -1,12 +1,11 @@ -/* $NetBSD: extern.h,v 1.1 2007/02/18 22:13:42 rmind Exp $ */ -/* $OpenBSD: extern.h,v 1.4 2006/05/25 03:20:32 ray Exp $ */ +/* $OpenBSD: extern.h,v 1.5 2009/06/07 13:29:50 ray Exp $ */ /* * Written by Raymond Lai . * Public domain. */ -extern FILE *outfile; /* file to save changes to */ +extern FILE *outfp; /* file to save changes to */ extern const char *tmpdir; int eparse(const char *, const char *, const char *); diff -ru /home/bapt/dev/NetBSD/src/usr.bin/sdiff/Makefile ./Makefile --- /home/bapt/dev/NetBSD/src/usr.bin/sdiff/Makefile 2015-01-29 04:28:19.000000000 +0100 +++ ./Makefile 2016-04-18 22:26:05.364352000 +0200 @@ -1,12 +1,16 @@ -# $NetBSD: Makefile,v 1.3 2015/01/29 03:28:19 christos Exp $ +# $FreeBSD$ -WARNS?= 2 # XXX -Wcast-qual issues +.include PROG= sdiff SRCS= common.c edit.c sdiff.c -CPPFLAGS+=-D_OPENBSD_SOURCE +WARNS= 3 -LDADD+= -lutil -DPADD+= ${LIBUTIL} +LIBADD= util +MAN1= sdiff.1 -.include +.if ${MK_TESTS} != "no" +SUBDIR+= tests +.endif + +.include Only in .: sdiff Only in .: sdiff-netbsd.diff Only in .: sdiff-openbsd.diff diff -ru /home/bapt/dev/NetBSD/src/usr.bin/sdiff/sdiff.1 ./sdiff.1 --- /home/bapt/dev/NetBSD/src/usr.bin/sdiff/sdiff.1 2014-03-18 19:20:45.000000000 +0100 +++ ./sdiff.1 2016-04-16 22:11:15.663716000 +0200 @@ -1,10 +1,10 @@ -.\" $NetBSD: sdiff.1,v 1.4 2014/03/18 18:20:45 riastradh Exp $ -.\" $OpenBSD: sdiff.1,v 1.11 2007/02/22 02:50:56 ray Exp $ +.\" $FreeBSD$ +.\" $OpenBSD: sdiff.1,v 1.15 2007/06/29 14:48:07 jmc Exp $ .\" .\" Written by Raymond Lai . .\" Public domain. .\" -.Dd February 21, 2007 +.Dd $Mdocdate: July 5 2012 $ .Dt SDIFF 1 .Os .Sh NAME @@ -23,11 +23,11 @@ displays two files side by side, with any differences between the two highlighted as follows: new lines are marked with -.Sq \*[Gt] ; +.Sq \*(Gt ; deleted lines are marked with -.Sq \*[Lt] ; +.Sq \*(Lt ; and changed lines are marked with -.Sq | . +.Sq \*(Ba . .Pp .Nm can also be used to interactively merge two files, @@ -38,9 +38,9 @@ .Pp The options are: .Bl -tag -width Ds -.It Fl l +.It Fl l -left-column Only print the left column for identical lines. -.It Fl o Ar outfile +.It Fl o -output Ar outfile Interactively merge .Ar file1 and @@ -57,9 +57,9 @@ .Pp The commands are as follows: .Bl -tag -width Ds -.It Cm l +.It Cm l | 1 Choose left set of diffs. -.It Cm r +.It Cm r | 2 Choose right set of diffs. .It Cm s Silent mode \(en identical lines are not printed. @@ -79,9 +79,9 @@ Quit .Nm . .El -.It Fl s +.It Fl s -suppress-common-lines Skip identical lines. -.It Fl w Ar width +.It Fl w -width Ar width Print a maximum of .Ar width characters on each line. @@ -92,32 +92,44 @@ .Xr diff 1 are: .Bl -tag -width Ds -.It Fl a +.It Fl a -text Treat .Ar file1 and .Ar file2 as text files. -.It Fl b +.It Fl b -ignore-space-change Ignore trailing blank spaces. -.It Fl d +.It Fl d -minimal Minimize diff size. -.It Fl I Ar regexp +.It Fl I -ignore-matching-lines Ar regexp Ignore line changes matching .Ar regexp . All lines in the change must match .Ar regexp for the change to be ignored. -.It Fl i +.It Fl i -ignore-case Do a case-insensitive comparison. -.It Fl t +.It Fl t -expand-tabs Expand tabs to spaces. -.It Fl W -Ignore all spaces -(the -.Fl w -flag is passed to -.Xr diff 1 ) . +.It Fl W -ignore-all-space +Ignore all spaces. +.It Fl B -ignore-blank-lines +Ignore blank lines. +.It Fl E -ignore-tab-expansion +Treat tabs and eight spaces as the same. +.It Fl t -ignore-tabs +Ignore tabs. +.It Fl H -speed-large-files +Assume scattered small changes in a large file. +.It Fl -ignore-file-name-case +Ignore the case of file names. +.It Fl -no-ignore-file-name-case +Do not ignore file name case. +.It Fl -strip-trailing-cr +Skip identical lines. +.It Fl -tabsize Ar NUM +Change the size of tabs (default is 8.) .El .Sh ENVIRONMENT .Bl -tag -width Ds @@ -145,6 +157,7 @@ .Pa /tmp . .El .Sh SEE ALSO +.Xr cmp 1 , .Xr diff 1 , .Xr diff3 1 , .Xr vi 1 , @@ -152,16 +165,10 @@ .Sh AUTHORS .Nm was written from scratch for the public domain by -.An Ray Lai Aq Mt ray@cyth.net . +.An Ray Lai Aq ray@cyth.net . .Sh CAVEATS -Although undocumented, -.Nm -supports all options supported by GNU sdiff. -Some options require GNU diff. .Pp Tabs are treated as anywhere from one to eight characters wide, depending on the current column. Terminals that treat tabs as eight characters wide will look best. -.Sh BUGS -.Nm -may not work with binary data. + Only in .: sdiff.1.gz diff -ru /home/bapt/dev/NetBSD/src/usr.bin/sdiff/sdiff.c ./sdiff.c --- /home/bapt/dev/NetBSD/src/usr.bin/sdiff/sdiff.c 2009-04-13 09:19:55.000000000 +0200 +++ ./sdiff.c 2016-04-18 23:29:34.031467000 +0200 @@ -1,11 +1,13 @@ -/* $NetBSD: sdiff.c,v 1.2 2009/04/13 07:19:55 lukem Exp $ */ -/* $OpenBSD: sdiff.c,v 1.20 2006/09/19 05:52:23 otto Exp $ */ +/* $OpenBSD: sdiff.c,v 1.36 2015/12/29 19:04:46 gsoares Exp $ */ /* * Written by Raymond Lai . * Public domain. */ +#include +__FBSDID("$FreeBSD$"); + #include #include #include @@ -23,21 +25,28 @@ #include #include #include -#include + +#include +#include #include "common.h" #include "extern.h" -#define WIDTH 130 +#define DIFF_PATH "/usr/bin/diff" + +#define WIDTH 126 /* * Each column must be at least one character wide, plus three * characters between the columns (space, [<|>], space). */ #define WIDTH_MIN 5 +/* 3 kilobytes of chars */ +#define MAX_CHECK 768 + /* A single diff line. */ struct diffline { - SIMPLEQ_ENTRY(diffline) diffentries; + STAILQ_ENTRY(diffline) diffentries; char *left; char div; char *right; @@ -46,6 +55,8 @@ static void astrcat(char **, const char *); static void enqueue(char *, char, char *); static char *mktmpcpy(const char *); +static int istextfile(FILE *); +static void binexec(char *, char *, char *) __dead2; static void freediff(struct diffline *); static void int_usage(void); static int parsecmd(FILE *, FILE *, FILE *); @@ -56,36 +67,105 @@ static void println(const char *, const char, const char *); static void processq(void); static void prompt(const char *, const char *); -__dead static void usage(void); +static void usage(void) __dead2; +static void fail(char*) __dead2; static char *xfgets(FILE *); -SIMPLEQ_HEAD(, diffline) diffhead = SIMPLEQ_HEAD_INITIALIZER(diffhead); -size_t line_width; /* width of a line (two columns and divider) */ -size_t width; /* width of each column */ -size_t file1ln, file2ln; /* line number of file1 and file2 */ -int Iflag = 0; /* ignore sets matching regexp */ -int lflag; /* print only left column for identical lines */ -int sflag; /* skip identical lines */ -FILE *outfile; /* file to save changes to */ +static STAILQ_HEAD(, diffline) diffhead = STAILQ_HEAD_INITIALIZER(diffhead); +static size_t line_width; /* width of a line (two columns and divider) */ +static size_t width; /* width of each column */ +static size_t file1ln, file2ln; /* line number of file1 and file2 */ +static int Iflag = 0; /* ignore sets matching regexp */ +static int lflag; /* print only left column for identical lines */ +static int sflag; /* skip identical lines */ +FILE *outfp; /* file to save changes to */ const char *tmpdir; /* TMPDIR or /tmp */ +enum { + HELP_OPT = CHAR_MAX + 1, + NORMAL_OPT, + FCASE_SENSITIVE_OPT, + FCASE_IGNORE_OPT, + FROMFILE_OPT, + TOFILE_OPT, + UNIDIR_OPT, + STRIPCR_OPT, + HORIZ_OPT, + LEFTC_OPT, + SUPCL_OPT, + LF_OPT, + /* the following groupings must be in sequence */ + OLDGF_OPT, + NEWGF_OPT, + UNCGF_OPT, + CHGF_OPT, + OLDLF_OPT, + NEWLF_OPT, + UNCLF_OPT, + /* end order-sensitive enums */ + TSIZE_OPT, + HLINES_OPT, + LFILES_OPT, + DIFFPROG_OPT, + PIPE_FD, + /* pid from the diff parent (if applicable) */ + DIFF_PID, + + NOOP_OPT, +}; + static struct option longopts[] = { + /* options only processed in sdiff */ + { "left-column", no_argument, NULL, LEFTC_OPT }, + { "suppress-common-lines", no_argument, NULL, 's' }, + { "width", required_argument, NULL, 'w' }, + + { "output", required_argument, NULL, 'o' }, + { "diff-program", required_argument, NULL, DIFFPROG_OPT }, + + { "pipe-fd", required_argument, NULL, PIPE_FD }, + { "diff-pid", required_argument, NULL, DIFF_PID }, + /* Options processed by diff. */ + { "ignore-file-name-case", no_argument, NULL, FCASE_IGNORE_OPT }, + { "no-ignore-file-name-case", no_argument, NULL, FCASE_SENSITIVE_OPT }, + { "strip-trailing-cr", no_argument, NULL, STRIPCR_OPT }, + { "tabsize", required_argument, NULL, TSIZE_OPT }, + { "help", no_argument, NULL, HELP_OPT }, { "text", no_argument, NULL, 'a' }, { "ignore-blank-lines", no_argument, NULL, 'B' }, { "ignore-space-change", no_argument, NULL, 'b' }, { "minimal", no_argument, NULL, 'd' }, { "ignore-tab-expansion", no_argument, NULL, 'E' }, - { "diff-program", required_argument, NULL, 'F' }, - { "speed-large-files", no_argument, NULL, 'H' }, { "ignore-matching-lines", required_argument, NULL, 'I' }, - { "left-column", no_argument, NULL, 'l' }, - { "output", required_argument, NULL, 'o' }, - { "strip-trailing-cr", no_argument, NULL, 'S' }, - { "suppress-common-lines", no_argument, NULL, 's' }, + { "ignore-case", no_argument, NULL, 'i' }, { "expand-tabs", no_argument, NULL, 't' }, + { "speed-large-files", no_argument, NULL, 'H' }, { "ignore-all-space", no_argument, NULL, 'W' }, - { "width", required_argument, NULL, 'w' }, - { NULL, 0, NULL, 0 } + + { NULL, 0, NULL, '\0'} +}; + +static const char *help_msg[] = { + "\nusage: sdiff [-abdilstW] [-I regexp] [-o outfile] [-w width] file1 file2\n", + "\t-l, --left-column, Only print the left column for identical lines.", + "\t-o OUTFILE, --output=OUTFILE, nteractively merge file1 and file2 into outfile.", + "\t-s, --suppress-common-lines, Skip identical lines.", + "\t-w WIDTH, --width=WIDTH, Print a maximum of WIDTH characters on each line.", + "\tOptions passed to diff(1) are:", + "\t\t-a, --text, Treat file1 and file2 as text files.", + "\t\t-b, --ignore-trailing-cr, Ignore trailing blank spaces.", + "\t\t-d, --minimal, Minimize diff size.", + "\t\t-I RE, --ignore-matching-lines=RE, Ignore changes whose line matches RE.", + "\t\t-i, --ignore-case, Do a case-insensitive comparison.", + "\t\t-t, --expand-tabs Expand tabs to spaces.", + "\t\t-W, --ignore-all-spaces, Ignore all spaces.", + "\t\t--speed-large-files, Assume large file with scattered changes.", + "\t\t--strip-trailing-cr, Strip trailing carriage return.", + "\t\t--ignore-file-name-case, Ignore case of file names.", + "\t\t--no-ignore-file-name-case, Do not ignore file name case", + "\t\t--tabsize NUM, Change size of tabs (default 8.)", + + NULL, }; /* @@ -109,8 +189,10 @@ err(2, "error getting file status from %s", source_file); /* Regular file. */ - if (S_ISREG(sb.st_mode)) + if (S_ISREG(sb.st_mode)) { + close(ifd); return (NULL); + } } else { /* If ``-'' does not exist the user meant stdin. */ if (errno == ENOENT && strcmp(source_file, "-") == 0) @@ -148,18 +230,21 @@ FAIL: unlink(target_file); - exit(2); + exit(1); } int main(int argc, char **argv) { - FILE *diffpipe, *file1, *file2; + FILE *diffpipe=NULL, *file1, *file2; size_t diffargc = 0, wflag = WIDTH; - int ch, fd[2], status; - pid_t pid; - char **diffargv, *diffprog = "diff", *filename1, *filename2, - *tmp1, *tmp2, *s1, *s2; + int ch, fd[2] = {-1}, status; + pid_t pid=0; pid_t ppid =-1; + const char *outfile = NULL; + struct option *popt; + char **diffargv, *diffprog = DIFF_PATH, *filename1, *filename2, + *tmp1, *tmp2, *s1, *s2; + int i; /* * Process diff flags. @@ -172,83 +257,106 @@ * waste some memory; however we need an extra space for the * NULL at the end, so it sort of works out. */ - if (!(diffargv = malloc(sizeof(char **) * argc * 2))) + if (!(diffargv = calloc(argc, sizeof(char **) * 2))) err(2, "main"); /* Add first argument, the program name. */ diffargv[diffargc++] = diffprog; + /* create a dynamic string for merging single-switch options */ + if ( asprintf(&diffargv[diffargc++], "-") < 0 ) + err(2, "main"); + while ((ch = getopt_long(argc, argv, "aBbdEHI:ilo:stWw:", longopts, NULL)) != -1) { const char *errstr; switch (ch) { + /* only compatible --long-name-form with diff */ + case FCASE_IGNORE_OPT: + case FCASE_SENSITIVE_OPT: + case STRIPCR_OPT: + case TSIZE_OPT: + case 'S': + break; + /* combine no-arg single switches */ case 'a': - diffargv[diffargc++] = "-a"; - break; case 'B': - diffargv[diffargc++] = "-B"; - break; case 'b': - diffargv[diffargc++] = "-b"; - break; case 'd': - diffargv[diffargc++] = "-d"; - break; case 'E': - diffargv[diffargc++] = "-E"; + case 'i': + case 't': + case 'H': + case 'W': + for(popt = longopts; ch != popt->val && popt->name != NULL; popt++); + diffargv[1] = realloc(diffargv[1], sizeof(char) * strlen(diffargv[1]) + 2); + /* + * In diff, the 'W' option is 'w' and the 'w' is 'W'. + */ + if (ch == 'W') + sprintf(diffargv[1], "%sw", diffargv[1]); + else + sprintf(diffargv[1], "%s%c", diffargv[1], ch); break; - case 'F': + case DIFFPROG_OPT: diffargv[0] = diffprog = optarg; break; - case 'H': - diffargv[diffargc++] = "-H"; - break; case 'I': Iflag = 1; diffargv[diffargc++] = "-I"; diffargv[diffargc++] = optarg; break; - case 'i': - diffargv[diffargc++] = "-i"; - break; case 'l': lflag = 1; break; case 'o': - if ((outfile = fopen(optarg, "w")) == NULL) - err(2, "could not open: %s", optarg); - break; - case 'S': - diffargv[diffargc++] = "--strip-trailing-cr"; + outfile = optarg; break; case 's': sflag = 1; break; - case 't': - diffargv[diffargc++] = "-t"; - break; - case 'W': - diffargv[diffargc++] = "-w"; - break; case 'w': wflag = strtonum(optarg, WIDTH_MIN, INT_MAX, &errstr); if (errstr) errx(2, "width is %s: %s", errstr, optarg); break; + case DIFF_PID: + ppid = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr) + errx(2, "diff pid value is %s: %s", errstr, optarg); + break; + case HELP_OPT: + for (i = 0; help_msg[i] != NULL; i++) + printf("%s\n", help_msg[i]); + exit(0); + break; default: usage(); + break; } + } + /* no single switches were used */ + if (strcmp(diffargv[1], "-") == 0 ) { + for ( i = 1; i < argc-1; i++) { + diffargv[i] = diffargv[i+1]; + } + diffargv[diffargc-1] = NULL; + diffargc--; } + argc -= optind; argv += optind; if (argc != 2) usage(); - if ((tmpdir = getenv("TMPDIR")) == NULL) + if (outfile && (outfp = fopen(outfile, "w")) == NULL) + err(2, "could not open: %s", optarg); + + if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') tmpdir = _PATH_TMP; filename1 = argv[0]; @@ -283,41 +391,58 @@ /* Subtract column divider and divide by two. */ width = (wflag - 3) / 2; /* Make sure line_width can fit in size_t. */ - if (width > (SIZE_T_MAX - 3) / 2) + if (width > (SIZE_MAX - 3) / 2) errx(2, "width is too large: %zu", width); line_width = width * 2 + 3; - if (pipe(fd)) - err(2, "pipe"); + if (ppid == -1 ) { + if (pipe(fd)) + err(2, "pipe"); + + switch (pid = fork()) { + case 0: + /* child */ + /* We don't read from the pipe. */ + close(fd[0]); + if (dup2(fd[1], STDOUT_FILENO) == -1) + err(2, "child could not duplicate descriptor"); + /* Free unused descriptor. */ + close(fd[1]); + execvp(diffprog, diffargv); + err(2, "could not execute diff: %s", diffprog); + break; + case -1: + err(2, "could not fork"); + break; + } - switch(pid = fork()) { - case 0: - /* child */ - /* We don't read from the pipe. */ - close(fd[0]); - if (dup2(fd[1], STDOUT_FILENO) == -1) - err(2, "child could not duplicate descriptor"); - /* Free unused descriptor. */ + /* parent */ + /* We don't write to the pipe. */ close(fd[1]); - execvp(diffprog, diffargv); - err(2, "could not execute diff: %s", diffprog); - case -1: - err(2, "could not fork"); + /* Open pipe to diff command. */ + if ((diffpipe = fdopen(fd[0], "r")) == NULL) + err(2, "could not open diff pipe"); } - - /* parent */ - /* We don't write to the pipe. */ - close(fd[1]); - - /* Open pipe to diff command. */ - if ((diffpipe = fdopen(fd[0], "r")) == NULL) - err(2, "could not open diff pipe"); if ((file1 = fopen(filename1, "r")) == NULL) err(2, "could not open %s", filename1); if ((file2 = fopen(filename2, "r")) == NULL) err(2, "could not open %s", filename2); - + if (!istextfile(file1) || !istextfile(file2)) { + /* Close open files and pipe, delete temps */ + fclose(file1); + fclose(file2); + fclose(diffpipe); + if (tmp1) + if (unlink(tmp1)) + warn("Error deleting %s.", tmp1); + if (tmp2) + if (unlink(tmp2)) + warn("Error deleting %s.", tmp2); + free(tmp1); + free(tmp2); + binexec(diffprog, filename1, filename2); + } /* Line numbers start at one. */ file1ln = file2ln = 1; @@ -329,15 +454,15 @@ /* Wait for diff to exit. */ if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) || WEXITSTATUS(status) >= 2) - err(2, "diff exited abnormally"); + err(2, "diff exited abnormally."); /* Delete and free unneeded temporary files. */ if (tmp1) if (unlink(tmp1)) - warn("error deleting %s", tmp1); + warn("Error deleting %s.", tmp1); if (tmp2) if (unlink(tmp2)) - warn("error deleting %s", tmp2); + warn("Error deleting %s.", tmp2); free(tmp1); free(tmp2); filename1 = filename2 = tmp1 = tmp2 = NULL; @@ -365,6 +490,44 @@ } /* + * When sdiff/zsdiff detects a binary file as input, executes them with + * diff/zdiff to maintain the same behavior as GNU sdiff with binary input. + */ +static void +binexec(char *diffprog, char *f1, char *f2) +{ + + char *args[] = {diffprog, f1, f2, (char *) 0}; + execv(diffprog, args); + + /* If execv() fails, sdiff's execution will continue below. */ + errx(1, "Could not execute diff process.\n"); +} + +/* + * Checks whether a file appears to be a text file. + */ +static int +istextfile(FILE *f) +{ + int i; + char ch; + + if (f == NULL) + return (1); + rewind(f); + for (i = 0; i <= MAX_CHECK || ch != EOF; i++) { + ch = fgetc(f); + if (ch == '\0') { + rewind(f); + return (0); + } + } + rewind(f); + return (1); +} + +/* * Prints an individual column (left or right), taking into account * that tabs are variable-width. Takes a string, the current column * the cursor is on the screen, and the maximum value of the column. @@ -383,7 +546,7 @@ * If rounding to next multiple of eight causes * an integer overflow, just return. */ - if (*col > SIZE_T_MAX - 8) + if (*col > SIZE_MAX - 8) return; /* Round to next multiple of eight. */ @@ -397,11 +560,9 @@ return; *col = new_col; break; - default: ++(*col); } - putchar(*s); } } @@ -423,45 +584,37 @@ const char *p; /* Skip leading whitespace. */ - for (p = cmd; isspace((int)(*p)); ++p) + for (p = cmd; isspace(*p); ++p) ; - switch (*p) { case 'e': /* Skip `e'. */ ++p; - if (eparse(p, s1, s2) == -1) goto USAGE; break; - case 'l': + case '1': /* Choose left column as-is. */ if (s1 != NULL) - fprintf(outfile, "%s\n", s1); - + fprintf(outfp, "%s\n", s1); /* End of command parsing. */ break; - case 'q': goto QUIT; - case 'r': + case '2': /* Choose right column as-is. */ if (s2 != NULL) - fprintf(outfile, "%s\n", s2); - + fprintf(outfp, "%s\n", s2); /* End of command parsing. */ break; - case 's': sflag = 1; goto PROMPT; - case 'v': sflag = 0; /* FALLTHROUGH */ - default: /* Interactive usage help. */ USAGE: @@ -472,7 +625,6 @@ /* Prompt user again. */ continue; } - free(cmd); return; } @@ -482,7 +634,7 @@ * should quit. */ QUIT: - fclose(outfile); + fclose(outfp); exit(0); } @@ -496,7 +648,7 @@ * Takes into account that tabs can take multiple columns. */ static void -println(const char *s1, const char divc, const char *s2) +println(const char *s1, const char div, const char *s2) { size_t col; @@ -508,25 +660,25 @@ } - /* Only print left column. */ - if (divc == ' ' && !s2) { - putchar('\n'); - return; - } - /* Otherwise, we pad this column up to width. */ for (; col < width; ++col) putchar(' '); + /* Only print left column. */ + if (div == ' ' && !s2) { + printf(" (\n"); + return; + } + /* * Print column divider. If there is no second column, we don't * need to add the space for padding. */ if (!s2) { - printf(" %c\n", divc); + printf(" %c\n", div); return; } - printf(" %c ", divc); + printf(" %c ", div); col += 3; /* Skip angle bracket and space. */ @@ -579,7 +731,7 @@ p = line; /* Go to character after line number. */ - while (isdigit((int)(*p))) + while (isdigit(*p)) ++p; c = *p; *p++ = 0; @@ -589,10 +741,9 @@ /* A range is specified for file1. */ if (c == ',') { - q = p; /* Go to character after file2end. */ - while (isdigit((int)(*p))) + while (isdigit(*p)) ++p; c = *p; *p++ = 0; @@ -601,7 +752,6 @@ errx(2, "file1 end is %s: %s", errstr, line); if (file1start > file1end) errx(2, "invalid line range in file1: %s", line); - } else file1end = file1start; @@ -612,7 +762,7 @@ q = p; /* Go to character after line number. */ - while (isdigit((int)(*p))) + while (isdigit(*p)) ++p; c = *p; *p++ = 0; @@ -642,7 +792,7 @@ if (file1start != file1end) errx(2, "append cannot have a file1 range: %s", line); - if (file1start == SIZE_T_MAX) + if (file1start == SIZE_MAX) errx(2, "file1 line range too high: %s", line); file1start = ++file1end; } @@ -654,7 +804,7 @@ if (file2start != file2end) errx(2, "delete cannot have a file2 range: %s", line); - if (file2start == SIZE_T_MAX) + if (file2start == SIZE_MAX) errx(2, "file2 line range too high: %s", line); file2start = ++file2end; } @@ -720,25 +870,25 @@ printa(file2, file2end); n = file2end - file2start + 1; break; - case 'c': printc(file1, file1end, file2, file2end); n = file1end - file1start + 1 + 1 + file2end - file2start + 1; break; - case 'd': printd(file1, file1end); n = file1end - file1start + 1; break; - default: errx(2, "invalid diff command: %c: %s", cmd, line); } + free(line); /* Skip to next ed line. */ - while (n--) - if (!xfgets(diffpipe)) + while (n--) { + if (!(line = xfgets(diffpipe))) errx(2, "diff ended early"); + free(line); + } return (0); } @@ -747,16 +897,16 @@ * Queues up a diff line. */ static void -enqueue(char *left, char divc, char *right) +enqueue(char *left, char div, char *right) { struct diffline *diffp; if (!(diffp = malloc(sizeof(struct diffline)))) err(2, "enqueue"); diffp->left = left; - diffp->div = divc; + diffp->div = div; diffp->right = right; - SIMPLEQ_INSERT_TAIL(&diffhead, diffp, diffentries); + STAILQ_INSERT_TAIL(&diffhead, diffp, diffentries); } /* @@ -765,6 +915,7 @@ static void freediff(struct diffline *diffp) { + free(diffp->left); free(diffp->right); free(diffp); @@ -787,7 +938,6 @@ static const char *oldstr = NULL; char *newstr; - /* * First string is NULL, so just copy append. */ @@ -847,11 +997,11 @@ char divc, *left, *right; /* Don't process empty queue. */ - if (SIMPLEQ_EMPTY(&diffhead)) + if (STAILQ_EMPTY(&diffhead)) return; /* Remember the divider. */ - divc = SIMPLEQ_FIRST(&diffhead)->div; + divc = STAILQ_FIRST(&diffhead)->div; left = NULL; right = NULL; @@ -859,7 +1009,7 @@ * Go through set of diffs, concatenating each line in left or * right column into two long strings, `left' and `right'. */ - SIMPLEQ_FOREACH(diffp, &diffhead, diffentries) { + STAILQ_FOREACH(diffp, &diffhead, diffentries) { /* * Print changed lines if -s was given, * print all lines if -s was not given. @@ -876,17 +1026,17 @@ } /* Empty queue and free each diff line and its elements. */ - while (!SIMPLEQ_EMPTY(&diffhead)) { - diffp = SIMPLEQ_FIRST(&diffhead); - SIMPLEQ_REMOVE_HEAD(&diffhead, diffentries); + while (!STAILQ_EMPTY(&diffhead)) { + diffp = STAILQ_FIRST(&diffhead); + STAILQ_REMOVE_HEAD(&diffhead, diffentries); freediff(diffp); } - /* Write to outfile, prompting user if lines are different. */ - if (outfile) + /* Write to outfp, prompting user if lines are different. */ + if (outfp) switch (divc) { case ' ': case '(': case ')': - fprintf(outfile, "%s\n", left); + fprintf(outfp, "%s\n", left); break; case '|': case '<': case '>': prompt(left, right); @@ -913,7 +1063,6 @@ errx(2, "append ended early"); enqueue(NULL, '>', line); } - processq(); } @@ -925,10 +1074,10 @@ printc(FILE *file1, size_t file1end, FILE *file2, size_t file2end) { struct fileline { - SIMPLEQ_ENTRY(fileline) fileentries; + STAILQ_ENTRY(fileline) fileentries; char *line; }; - SIMPLEQ_HEAD(, fileline) delqhead = SIMPLEQ_HEAD_INITIALIZER(delqhead); + STAILQ_HEAD(, fileline) delqhead = STAILQ_HEAD_INITIALIZER(delqhead); /* Read lines to be deleted. */ for (; file1ln <= file1end; ++file1ln) { @@ -943,11 +1092,11 @@ if (!(linep = malloc(sizeof(struct fileline)))) err(2, "printc"); linep->line = line1; - SIMPLEQ_INSERT_TAIL(&delqhead, linep, fileentries); + STAILQ_INSERT_TAIL(&delqhead, linep, fileentries); } /* Process changed lines.. */ - for (; !SIMPLEQ_EMPTY(&delqhead) && file2ln <= file2end; + for (; !STAILQ_EMPTY(&delqhead) && file2ln <= file2end; ++file2ln) { struct fileline *del; char *add; @@ -956,9 +1105,9 @@ if (!(add = xfgets(file2))) errx(2, "error reading add in change"); - del = SIMPLEQ_FIRST(&delqhead); + del = STAILQ_FIRST(&delqhead); enqueue(del->line, '|', add); - SIMPLEQ_REMOVE_HEAD(&delqhead, fileentries); + STAILQ_REMOVE_HEAD(&delqhead, fileentries); /* * Free fileline structure but not its elements since * they are queued up. @@ -980,12 +1129,12 @@ processq(); /* Process remaining lines to delete. */ - while (!SIMPLEQ_EMPTY(&delqhead)) { + while (!STAILQ_EMPTY(&delqhead)) { struct fileline *filep; - filep = SIMPLEQ_FIRST(&delqhead); + filep = STAILQ_FIRST(&delqhead); enqueue(filep->line, '<', NULL); - SIMPLEQ_REMOVE_HEAD(&delqhead, fileentries); + STAILQ_REMOVE_HEAD(&delqhead, fileentries); free(filep); } processq(); @@ -1001,7 +1150,6 @@ /* Print out lines file1ln to line2. */ for (; file1ln <= file1end; ++file1ln) { - /* XXX - Why can't this handle stdin? */ if (!(line1 = xfgets(file1))) errx(2, "file1 ended early in delete"); enqueue(line1, '<', NULL); @@ -1015,12 +1163,13 @@ static void int_usage(void) { + puts("e:\tedit blank diff\n" "eb:\tedit both diffs concatenated\n" "el:\tedit left diff\n" "er:\tedit right diff\n" - "l:\tchoose left diff\n" - "r:\tchoose right diff\n" + "l | 1:\tchoose left diff\n" + "r | 2:\tchoose right diff\n" "s:\tsilent mode--don't print identical lines\n" "v:\tverbose mode--print identical lines\n" "q:\tquit"); @@ -1029,10 +1178,9 @@ static void usage(void) { - extern char *__progname; fprintf(stderr, - "usage: %s [-abdilstW] [-I regexp] [-o outfile] [-w width] file1 file2\n", - __progname); - exit(2); + "usage: sdiff [-abdilstW] [-I regexp] [-o outfile] [-w width] file1" + " file2\n"); + exit(1); } Only in .: sdiff.debug Only in .: sdiff.full Only in .: sdiff.o Only in .: tests