svn commit: r298823 - in head: gnu/usr.bin gnu/usr.bin/sdiff usr.bin usr.bin/sdiff usr.bin/sdiff/tests
Kamil Czekirda
kczekirda at gmail.com
Wed May 4 05:55:18 UTC 2016
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 <bapt at 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 <ray at 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 <ray at 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 <ray at 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 <ray at 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 <ray at 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 ray at 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 <ray at 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 at freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/svn-src-head
> To unsubscribe, send any mail to "svn-src-head-unsubscribe at freebsd.org"
>
More information about the svn-src-head
mailing list