summaryrefslogtreecommitdiffstats
path: root/usr.bin/sdiff/edit.c
diff options
context:
space:
mode:
authorbapt <bapt@FreeBSD.org>2016-04-29 23:27:15 +0000
committerbapt <bapt@FreeBSD.org>2016-04-29 23:27:15 +0000
commit8f5c11fdbe0c2d8d7434ca656cae0d4c676ee4af (patch)
tree7ec38e45cbfa9d445907fa348017b10854448f2a /usr.bin/sdiff/edit.c
parent27a52ce3e3da09854ac99ae8631add209493c47e (diff)
downloadFreeBSD-src-8f5c11fdbe0c2d8d7434ca656cae0d4c676ee4af.zip
FreeBSD-src-8f5c11fdbe0c2d8d7434ca656cae0d4c676ee4af.tar.gz
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)
Diffstat (limited to 'usr.bin/sdiff/edit.c')
-rw-r--r--usr.bin/sdiff/edit.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/usr.bin/sdiff/edit.c b/usr.bin/sdiff/edit.c
new file mode 100644
index 0000000..4d7fb5b
--- /dev/null
+++ b/usr.bin/sdiff/edit.c
@@ -0,0 +1,209 @@
+/* $OpenBSD: edit.c,v 1.19 2009/06/07 13:29:50 ray Exp $ */
+
+/*
+ * Written by Raymond Lai <ray@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);
+}
OpenPOWER on IntegriCloud