Hi, make ftp stops here since r298823:
===> usr.bin/sdiff/tests (distribute) cd /usr/src/usr.bin/sdiff/tests; make install -DNO_SUBDIR DESTDIR=/usr/src/release/dist/tests SHARED=copies install -o root -g wheel -m 555 sdiff /usr/src/release/dist/tests/usr/tests/usr.bin/sdiff/sdiff install: /usr/src/release/dist/tests/usr/tests/usr.bin/sdiff/sdiff: No such file or directory *** Error code 71 Stop. make[8]: stopped in /usr/src/usr.bin/sdiff/tests *** Error code 1 Stop. make[7]: stopped in /usr/src/usr.bin/sdiff/tests *** Error code 1 Stop. make[6]: stopped in /usr/src/usr.bin/sdiff *** Error code 1 Stop. make[5]: stopped in /usr/src/usr.bin *** Error code 1 Stop. make[4]: stopped in /usr/src *** Error code 1 Stop. make[3]: stopped in /usr/src *** Error code 1 Stop. make[2]: stopped in /usr/src *** Error code 1 Stop. make[1]: stopped in /usr/src *** Error code 1 Stop. make: stopped in /usr/src/release 2016-04-30 1:27 GMT+02:00 Baptiste Daroussin <b...@freebsd.org>: > Author: bapt > Date: Fri Apr 29 23:27:15 2016 > New Revision: 298823 > URL: https://svnweb.freebsd.org/changeset/base/298823 > > Log: > import sdiff(1) from GSoC 2012 > > Import sdiff(1) from the diff version written by Raymond Lai, > improved during GSoC 2012 by Jesse Hagewood. > > Compared to the version done in during that summer of code: > - Remove the zlib frontend: zsdiff > - Compatible output (column size and separators) with GNU sdiff > > Compared to GNU sdiff in ports: > - The only difference is padding using spaces vs tabs > > Compared to OpenBSD and NetBSD import: > - Implement missing options (including long options) from GNU sdiff > - Improved support for the edition mode (signal handling) > - Output visually compatible with GNU sdiff: size of columns > > While here import regression tests from NetBSD adapted to fit the output > as > expected by GNU sdiff > > Reviewed by: emaste (in part) > Obtained from: OpenBSD, NetBSD, GSoC 2012 > Relnotes: yes > Differential Revision: https://reviews.freebsd.org/D5981 > Differential Revision: https://reviews.freebsd.org/D6032 (diff > with NetBSD version) > Differential Revision: https://reviews.freebsd.org/D6033 (diff > with OpenBSD version) > > Added: > head/usr.bin/sdiff/ > head/usr.bin/sdiff/Makefile (contents, props changed) > head/usr.bin/sdiff/common.c (contents, props changed) > head/usr.bin/sdiff/common.h (contents, props changed) > head/usr.bin/sdiff/edit.c (contents, props changed) > head/usr.bin/sdiff/extern.h (contents, props changed) > head/usr.bin/sdiff/sdiff.1 (contents, props changed) > head/usr.bin/sdiff/sdiff.c (contents, props changed) > head/usr.bin/sdiff/tests/ > head/usr.bin/sdiff/tests/Makefile (contents, props changed) > head/usr.bin/sdiff/tests/d_dot.in (contents, props changed) > head/usr.bin/sdiff/tests/d_flags_l.out (contents, props changed) > head/usr.bin/sdiff/tests/d_flags_s.out (contents, props changed) > head/usr.bin/sdiff/tests/d_flags_w.out (contents, props changed) > head/usr.bin/sdiff/tests/d_iflags_a1.out (contents, props changed) > head/usr.bin/sdiff/tests/d_iflags_a2.out (contents, props changed) > head/usr.bin/sdiff/tests/d_iflags_b1.out (contents, props changed) > head/usr.bin/sdiff/tests/d_iflags_b2.out (contents, props changed) > head/usr.bin/sdiff/tests/d_iflags_c1.out (contents, props changed) > head/usr.bin/sdiff/tests/d_iflags_c2.out (contents, props changed) > head/usr.bin/sdiff/tests/d_iflags_d1.out (contents, props changed) > head/usr.bin/sdiff/tests/d_iflags_d2.out (contents, props changed) > head/usr.bin/sdiff/tests/d_input1 (contents, props changed) > head/usr.bin/sdiff/tests/d_input2 (contents, props changed) > head/usr.bin/sdiff/tests/d_oneline.in (contents, props changed) > head/usr.bin/sdiff/tests/d_oneline_a.out (contents, props changed) > head/usr.bin/sdiff/tests/d_oneline_b.out (contents, props changed) > head/usr.bin/sdiff/tests/d_same.out (contents, props changed) > head/usr.bin/sdiff/tests/d_short.out (contents, props changed) > head/usr.bin/sdiff/tests/d_tabends.in (contents, props changed) > head/usr.bin/sdiff/tests/d_tabends_a.out (contents, props changed) > head/usr.bin/sdiff/tests/d_tabends_b.out (contents, props changed) > head/usr.bin/sdiff/tests/d_tabends_c.out (contents, props changed) > head/usr.bin/sdiff/tests/d_tabs.out (contents, props changed) > head/usr.bin/sdiff/tests/d_tabs1.in (contents, props changed) > head/usr.bin/sdiff/tests/d_tabs2.in (contents, props changed) > head/usr.bin/sdiff/tests/sdiff.sh (contents, props changed) > Deleted: > head/gnu/usr.bin/sdiff/ > Modified: > head/gnu/usr.bin/Makefile > head/usr.bin/Makefile > > Modified: head/gnu/usr.bin/Makefile > > ============================================================================== > --- head/gnu/usr.bin/Makefile Fri Apr 29 22:43:11 2016 (r298822) > +++ head/gnu/usr.bin/Makefile Fri Apr 29 23:27:15 2016 (r298823) > @@ -13,7 +13,6 @@ SUBDIR= ${_binutils} \ > grep \ > ${_groff} \ > ${_rcs} \ > - sdiff \ > ${_tests} > > SUBDIR_DEPEND_gdb= ${_binutils} > > Modified: head/usr.bin/Makefile > > ============================================================================== > --- head/usr.bin/Makefile Fri Apr 29 22:43:11 2016 (r298822) > +++ head/usr.bin/Makefile Fri Apr 29 23:27:15 2016 (r298823) > @@ -134,6 +134,7 @@ SUBDIR= alias \ > rusers \ > rwall \ > script \ > + sdiff \ > sed \ > send-pr \ > seq \ > > Added: head/usr.bin/sdiff/Makefile > > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/usr.bin/sdiff/Makefile Fri Apr 29 23:27:15 2016 (r298823) > @@ -0,0 +1,16 @@ > +# $FreeBSD$ > + > +.include <src.opts.mk> > + > +PROG= sdiff > +SRCS= common.c edit.c sdiff.c > +WARNS= 3 > + > +LIBADD= util > +MAN1= sdiff.1 > + > +.if ${MK_TESTS} != "no" > +SUBDIR+= tests > +.endif > + > +.include <bsd.progs.mk> > > Added: head/usr.bin/sdiff/common.c > > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/usr.bin/sdiff/common.c Fri Apr 29 23:27:15 2016 (r298823) > @@ -0,0 +1,24 @@ > +/* $OpenBSD: common.c,v 1.4 2006/05/25 03:20:32 ray Exp $ */ > + > +/* > + * Written by Raymond Lai <r...@cyth.net>. > + * Public domain. > + */ > + > +#include <sys/cdefs.h> > +__FBSDID("$FreeBSD$"); > + > +#include <err.h> > +#include <stdlib.h> > +#include <unistd.h> > + > +#include "common.h" > + > +void > +cleanup(const char *filename) > +{ > + > + if (unlink(filename)) > + err(2, "could not delete: %s", filename); > + exit(2); > +} > > Added: head/usr.bin/sdiff/common.h > > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/usr.bin/sdiff/common.h Fri Apr 29 23:27:15 2016 (r298823) > @@ -0,0 +1,9 @@ > +/* $OpenBSD: common.h,v 1.2 2006/05/25 03:20:32 ray Exp $ */ > +/* $FreeBSD$ */ > + > +/* > + * Written by Raymond Lai <r...@cyth.net>. > + * Public domain. > + */ > + > +void cleanup(const char *) __dead2; > > Added: head/usr.bin/sdiff/edit.c > > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/usr.bin/sdiff/edit.c Fri Apr 29 23:27:15 2016 (r298823) > @@ -0,0 +1,209 @@ > +/* $OpenBSD: edit.c,v 1.19 2009/06/07 13:29:50 ray Exp $ */ > + > +/* > + * Written by Raymond Lai <r...@cyth.net>. > + * Public domain. > + */ > + > +#include <sys/cdefs.h> > +__FBSDID("$FreeBSD$"); > + > +#include <sys/types.h> > +#include <sys/wait.h> > + > +#include <ctype.h> > +#include <err.h> > +#include <errno.h> > +#include <paths.h> > +#include <signal.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > + > +#include "common.h" > +#include "extern.h" > + > +int editit(const char *); > + > +/* > + * 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. > + */ > +int > +editit(const char *pathname) > +{ > + char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p; > + sig_t sighup, sigint, sigquit, sigchld; > + pid_t pid; > + int saved_errno, st, ret = -1; > + > + 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; > + > + 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); > +} > + > +/* > + * Parse edit command. Returns 0 on success, -1 on error. > + */ > +int > +eparse(const char *cmd, const char *left, const char *right) > +{ > + FILE *file; > + size_t nread; > + int fd; > + char *filename; > + char buf[BUFSIZ], *text; > + > + /* Skip whitespace. */ > + while (isspace(*cmd)) > + ++cmd; > + > + text = NULL; > + switch (*cmd) { > + case '\0': > + /* Edit empty file. */ > + break; > + > + case 'b': > + /* Both strings. */ > + if (left == NULL) > + goto RIGHT; > + if (right == NULL) > + goto LEFT; > + > + /* Neither column is blank, so print both. */ > + if (asprintf(&text, "%s\n%s\n", left, right) == -1) > + err(2, "could not allocate memory"); > + break; > + > + case 'l': > +LEFT: > + /* Skip if there is no left column. */ > + if (left == NULL) > + break; > + > + if (asprintf(&text, "%s\n", left) == -1) > + err(2, "could not allocate memory"); > + > + break; > + > + case 'r': > +RIGHT: > + /* Skip if there is no right column. */ > + if (right == NULL) > + break; > + > + if (asprintf(&text, "%s\n", right) == -1) > + err(2, "could not allocate memory"); > + > + break; > + > + default: > + return (-1); > + } > + > + /* Create temp file. */ > + if (asprintf(&filename, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1) > + err(2, "asprintf"); > + if ((fd = mkstemp(filename)) == -1) > + err(2, "mkstemp"); > + if (text != NULL) { > + size_t len; > + ssize_t nwritten; > + > + len = strlen(text); > + if ((nwritten = write(fd, text, len)) == -1 || > + (size_t)nwritten != len) { > + warn("error writing to temp file"); > + cleanup(filename); > + } > + } > + close(fd); > + > + /* text is no longer used. */ > + free(text); > + > + /* Edit temp file. */ > + if (editit(filename) == -1) { > + warn("error editing %s", filename); > + cleanup(filename); > + } > + > + /* Open temporary file. */ > + if (!(file = fopen(filename, "r"))) { > + warn("could not open edited file: %s", filename); > + cleanup(filename); > + } > + > + /* 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) && > + (ferror(file) || !feof(file))) { > + warnx("error reading edited file: %s", filename); > + cleanup(filename); > + } > + > + /* > + * If we have nothing to read, break out of loop > + * instead of writing nothing. > + */ > + if (!nread) > + break; > + > + /* Write data we just read. */ > + nwritten = fwrite(buf, sizeof(*buf), nread, outfp); > + if (nwritten != nread) { > + warnx("error writing to output file"); > + cleanup(filename); > + } > + } > + > + /* We've reached the end of the temporary file, so remove it. */ > + if (unlink(filename)) > + warn("could not delete: %s", filename); > + fclose(file); > + > + free(filename); > + > + return (0); > +} > > Added: head/usr.bin/sdiff/extern.h > > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/usr.bin/sdiff/extern.h Fri Apr 29 23:27:15 2016 (r298823) > @@ -0,0 +1,12 @@ > +/* $OpenBSD: extern.h,v 1.5 2009/06/07 13:29:50 ray Exp $ */ > +/* $FreeBSD$ */ > + > +/* > + * Written by Raymond Lai <r...@cyth.net>. > + * Public domain. > + */ > + > +extern FILE *outfp; /* file to save changes to */ > +extern const char *tmpdir; > + > +int eparse(const char *, const char *, const char *); > > Added: head/usr.bin/sdiff/sdiff.1 > > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/usr.bin/sdiff/sdiff.1 Fri Apr 29 23:27:15 2016 (r298823) > @@ -0,0 +1,174 @@ > +.\" $FreeBSD$ > +.\" $OpenBSD: sdiff.1,v 1.15 2007/06/29 14:48:07 jmc Exp $ > +.\" > +.\" Written by Raymond Lai <r...@cyth.net>. > +.\" Public domain. > +.\" > +.Dd $Mdocdate: July 5 2012 $ > +.Dt SDIFF 1 > +.Os > +.Sh NAME > +.Nm sdiff > +.Nd side-by-side diff > +.Sh SYNOPSIS > +.Nm > +.Op Fl abdilstW > +.Op Fl I Ar regexp > +.Op Fl o Ar outfile > +.Op Fl w Ar width > +.Ar file1 > +.Ar file2 > +.Sh DESCRIPTION > +.Nm > +displays two files side by side, > +with any differences between the two highlighted as follows: > +new lines are marked with > +.Sq \*(Gt ; > +deleted lines are marked with > +.Sq \*(Lt ; > +and changed lines are marked with > +.Sq \*(Ba . > +.Pp > +.Nm > +can also be used to interactively merge two files, > +prompting at each set of differences. > +See the > +.Fl o > +option for an explanation. > +.Pp > +The options are: > +.Bl -tag -width Ds > +.It Fl l -left-column > +Only print the left column for identical lines. > +.It Fl o -output Ar outfile > +Interactively merge > +.Ar file1 > +and > +.Ar file2 > +into > +.Ar outfile . > +In this mode, the user is prompted for each set of differences. > +See > +.Ev EDITOR > +and > +.Ev VISUAL , > +below, > +for details of which editor, if any, is invoked. > +.Pp > +The commands are as follows: > +.Bl -tag -width Ds > +.It Cm l | 1 > +Choose left set of diffs. > +.It Cm r | 2 > +Choose right set of diffs. > +.It Cm s > +Silent mode \(en identical lines are not printed. > +.It Cm v > +Verbose mode \(en identical lines are printed. > +.It Cm e > +Start editing an empty file, which will be merged into > +.Ar outfile > +upon exiting the editor. > +.It Cm e Cm l > +Start editing file with left set of diffs. > +.It Cm e Cm r > +Start editing file with right set of diffs. > +.It Cm e Cm b > +Start editing file with both sets of diffs. > +.It Cm q > +Quit > +.Nm . > +.El > +.It Fl s -suppress-common-lines > +Skip identical lines. > +.It Fl w -width Ar width > +Print a maximum of > +.Ar width > +characters on each line. > +The default is 130 characters. > +.El > +.Pp > +Options passed to > +.Xr diff 1 > +are: > +.Bl -tag -width Ds > +.It Fl a -text > +Treat > +.Ar file1 > +and > +.Ar file2 > +as text files. > +.It Fl b -ignore-space-change > +Ignore trailing blank spaces. > +.It Fl d -minimal > +Minimize diff size. > +.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 -ignore-case > +Do a case-insensitive comparison. > +.It Fl t -expand-tabs > +Expand tabs to spaces. > +.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 > +.It Ev EDITOR , VISUAL > +Specifies an editor to use with the > +.Fl o > +option. > +If both > +.Ev EDITOR > +and > +.Ev VISUAL > +are set, > +.Ev VISUAL > +takes precedence. > +If neither > +.Ev EDITOR > +nor > +.Ev VISUAL > +are set, > +the default is > +.Xr vi 1 . > +.It Ev TMPDIR > +Specifies a directory for temporary files to be created. > +The default is > +.Pa /tmp . > +.El > +.Sh SEE ALSO > +.Xr cmp 1 , > +.Xr diff 1 , > +.Xr diff3 1 , > +.Xr vi 1 , > +.Xr re_format 7 > +.Sh AUTHORS > +.Nm > +was written from scratch for the public domain by > +.An Ray Lai Aq r...@cyth.net . > +.Sh CAVEATS > +.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. > + > > Added: head/usr.bin/sdiff/sdiff.c > > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/usr.bin/sdiff/sdiff.c Fri Apr 29 23:27:15 2016 (r298823) > @@ -0,0 +1,1184 @@ > +/* $OpenBSD: sdiff.c,v 1.36 2015/12/29 19:04:46 gsoares Exp $ */ > + > +/* > + * Written by Raymond Lai <r...@cyth.net>. > + * Public domain. > + */ > + > +#include <sys/cdefs.h> > +__FBSDID("$FreeBSD$"); > + > +#include <sys/param.h> > +#include <sys/queue.h> > +#include <sys/stat.h> > +#include <sys/types.h> > +#include <sys/wait.h> > + > +#include <ctype.h> > +#include <err.h> > +#include <errno.h> > +#include <fcntl.h> > +#include <getopt.h> > +#include <limits.h> > +#include <paths.h> > +#include <stdint.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <libutil.h> > + > +#include "common.h" > +#include "extern.h" > + > +#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 { > + STAILQ_ENTRY(diffline) diffentries; > + char *left; > + char div; > + char *right; > +}; > + > +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 *); > +static void printa(FILE *, size_t); > +static void printc(FILE *, size_t, FILE *, size_t); > +static void printcol(const char *, size_t *, const size_t); > +static void printd(FILE *, size_t); > +static void println(const char *, const char, const char *); > +static void processq(void); > +static void prompt(const char *, const char *); > +static void usage(void) __dead2; > +static char *xfgets(FILE *); > + > +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' }, > + { "ignore-matching-lines", required_argument, NULL, > 'I' }, > + { "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' }, > + > + { 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, > +}; > + > +/* > + * Create temporary file if source_file is not a regular file. > + * Returns temporary file name if one was malloced, NULL if unnecessary. > + */ > +static char * > +mktmpcpy(const char *source_file) > +{ > + struct stat sb; > + ssize_t rcount; > + int ifd, ofd; > + u_char buf[BUFSIZ]; > + char *target_file; > + > + /* Open input and output. */ > + ifd = open(source_file, O_RDONLY, 0); > + /* File was opened successfully. */ > + if (ifd != -1) { > + if (fstat(ifd, &sb) == -1) > + err(2, "error getting file status from %s", > source_file); > + > + /* Regular file. */ > + 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) > + ifd = STDIN_FILENO; > + else > + err(2, "error opening %s", source_file); > + } > + > + /* Not a regular file, so copy input into temporary file. */ > + if (asprintf(&target_file, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1) > + err(2, "asprintf"); > + if ((ofd = mkstemp(target_file)) == -1) { > + warn("error opening %s", target_file); > + goto FAIL; > + } > + while ((rcount = read(ifd, buf, sizeof(buf))) != -1 && > + rcount != 0) { > + ssize_t wcount; > + > + wcount = write(ofd, buf, (size_t)rcount); > + if (-1 == wcount || rcount != wcount) { > + warn("error writing to %s", target_file); > + goto FAIL; > + } > + } > + if (rcount == -1) { > + warn("error reading from %s", source_file); > + goto FAIL; > + } > + > + close(ifd); > + close(ofd); > + > + return (target_file); > + > +FAIL: > + unlink(target_file); > + exit(2); > +} > + > +int > +main(int argc, char **argv) > +{ > + FILE *diffpipe=NULL, *file1, *file2; > + size_t diffargc = 0, wflag = WIDTH; > + 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. > + */ > + /* > + * Allocate memory for diff arguments and NULL. > + * Each flag has at most one argument, so doubling argc gives an > + * upper limit of how many diff args can be passed. argv[0], > + * file1, and file2 won't have arguments so doubling them will > + * waste some memory; however we need an extra space for the > + * NULL at the end, so it sort of works out. > + */ > + 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': > + case 'B': > + case 'b': > + case 'd': > + case '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 DIFFPROG_OPT: > + diffargv[0] = diffprog = optarg; > + break; > + case 'I': > + Iflag = 1; > + diffargv[diffargc++] = "-I"; > + diffargv[diffargc++] = optarg; > + break; > + case 'l': > + lflag = 1; > + break; > + case 'o': > + outfile = optarg; > + break; > + case 's': > + sflag = 1; > + 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 (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]; > + filename2 = argv[1]; > + > + /* > + * Create temporary files for diff and sdiff to share if file1 > + * or file2 are not regular files. This allows sdiff and diff > + * to read the same inputs if one or both inputs are stdin. > + * > + * If any temporary files were created, their names would be > + * saved in tmp1 or tmp2. tmp1 should never equal tmp2. > + */ > + tmp1 = tmp2 = NULL; > + /* file1 and file2 are the same, so copy to same temp file. */ > + if (strcmp(filename1, filename2) == 0) { > + if ((tmp1 = mktmpcpy(filename1))) > + filename1 = filename2 = tmp1; > + /* Copy file1 and file2 into separate temp files. */ > + } else { > + if ((tmp1 = mktmpcpy(filename1))) > + filename1 = tmp1; > + if ((tmp2 = mktmpcpy(filename2))) > + filename2 = tmp2; > + } > + > + diffargv[diffargc++] = filename1; > + diffargv[diffargc++] = filename2; > + /* Add NULL to end of array to indicate end of array. */ > + diffargv[diffargc++] = NULL; > + > + /* Subtract column divider and divide by two. */ > + width = (wflag - 3) / 2; > + /* Make sure line_width can fit in size_t. */ > + if (width > (SIZE_MAX - 3) / 2) > + errx(2, "width is too large: %zu", width); > + line_width = width * 2 + 3; > + > + 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; > + } > + > + /* 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; > + > + /* Read and parse diff output. */ > + while (parsecmd(diffpipe, file1, file2) != EOF) > + ; > + fclose(diffpipe); > + > + /* Wait for diff to exit. */ > + if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) || > + WEXITSTATUS(status) >= 2) > + err(2, "diff exited abnormally."); > + > + /* Delete and free unneeded temporary files. */ > + if (tmp1) > + if (unlink(tmp1)) > + warn("Error deleting %s.", tmp1); > + if (tmp2) > + if (unlink(tmp2)) > + warn("Error deleting %s.", tmp2); > + free(tmp1); > + free(tmp2); > + filename1 = filename2 = tmp1 = tmp2 = NULL; > + > + /* No more diffs, so print common lines. */ > + if (lflag) > + while ((s1 = xfgets(file1))) > + enqueue(s1, ' ', NULL); > + else > + for (;;) { > + s1 = xfgets(file1); > + s2 = xfgets(file2); > + if (s1 || s2) > + enqueue(s1, ' ', s2); > + else > + break; > + } > + fclose(file1); > + fclose(file2); > + /* Process unmodified lines. */ > + processq(); > + > + /* Return diff exit status. */ > + return (WEXITSTATUS(status)); > +} > + > +/* > + * 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); > > *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** > _______________________________________________ > svn-src-head@freebsd.org mailing list > https://lists.freebsd.org/mailman/listinfo/svn-src-head > To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org" > _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"