From ede65127cb813cd1efc8c8237c69c4308a761b33 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Mon, 8 Jun 2020 15:07:04 -0700 Subject: feat: added dvtm underneath source tree --- bin/dvtm-editor.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ bin/dvtm-pager | 11 ++++ bin/dvtm-status | 16 +++++ 3 files changed, 207 insertions(+) create mode 100644 bin/dvtm-editor.c create mode 100755 bin/dvtm-pager create mode 100755 bin/dvtm-status (limited to 'bin') diff --git a/bin/dvtm-editor.c b/bin/dvtm-editor.c new file mode 100644 index 0000000..45a61b2 --- /dev/null +++ b/bin/dvtm-editor.c @@ -0,0 +1,180 @@ +/* Invoke $EDITOR as a filter. + * + * Copyright (c) 2016 Dmitry Bogatov + * Copyright (c) 2017 Marc André Tanner + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void error(const char *msg, ...) { + va_list ap; + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); + if (errno) + fprintf(stderr, ": %s", strerror(errno)); + fprintf(stderr, "\n"); +} + +int main(int argc, char *argv[]) +{ + int exit_status = EXIT_FAILURE, tmp_write = -1; + + const char *editor = getenv("DVTM_EDITOR"); + if (!editor) + editor = getenv("VISUAL"); + if (!editor) + editor = getenv("EDITOR"); + if (!editor) + editor = "vi"; + + char tempname[] = "/tmp/dvtm-editor.XXXXXX"; + if ((tmp_write = mkstemp(tempname)) == -1) { + error("failed to open temporary file `%s'", tempname); + goto err; + } + + /* POSIX does not mandates modes of temporary file. */ + if (fchmod(tmp_write, 0600) == -1) { + error("failed to change mode of temporary file `%s'", tempname); + goto err; + } + + char buffer[2048]; + ssize_t bytes; + while ((bytes = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) { + do { + ssize_t written = write(tmp_write, buffer, bytes); + if (written == -1) { + error("failed to write data to temporary file `%s'", + tempname); + goto err; + } + bytes -= written; + } while (bytes > 0); + } + + if (fsync(tmp_write) == -1) { + error("failed to fsync temporary file `%s'", tempname); + goto err; + } + + struct stat stat_before; + if (fstat(tmp_write, &stat_before) == -1) { + error("failed to stat newly created temporary file `%s'", tempname); + goto err; + } + + if (close(tmp_write) == -1) { + error("failed to close temporary file `%s'", tempname); + goto err; + } + + pid_t pid = fork(); + if (pid == -1) { + error("failed to fork editor process"); + goto err; + } else if (pid == 0) { + int tty = open("/dev/tty", O_RDWR); + if (tty == -1) { + error("failed to open /dev/tty"); + _exit(1); + } + + if (dup2(tty, STDIN_FILENO) == -1) { + error("failed to set tty as stdin"); + _exit(1); + } + + if (dup2(tty, STDOUT_FILENO) == -1) { + error("failed to set tty as stdout"); + _exit(1); + } + + if (dup2(tty, STDERR_FILENO) == -1) { + error("failed to set tty as stderr"); + _exit(1); + } + + close(tty); + + const char *editor_argv[argc+2]; + editor_argv[0] = editor; + for (int i = 1; i < argc; i++) + editor_argv[i] = argv[i]; + editor_argv[argc] = tempname; + editor_argv[argc+1] = NULL; + + execvp(editor, (char* const*)editor_argv); + error("failed to exec editor process `%s'", editor); + _exit(127); + } + + int status; + if (waitpid(pid, &status, 0) == -1) { + error("waitpid failed"); + goto err; + } + if (!WIFEXITED(status)) { + error("editor invocation failed"); + goto err; + } + if ((status = WEXITSTATUS(status)) != 0) { + error("editor terminated with exit status: %d", status); + goto err; + } + + int tmp_read = open(tempname, O_RDONLY); + if (tmp_read == -1) { + error("failed to open for reading of edited temporary file `%s'", + tempname); + goto err; + } + + struct stat stat_after; + if (fstat(tmp_read, &stat_after) == -1) { + error("failed to stat edited temporary file `%s'", tempname); + goto err; + } + + if (stat_before.st_mtime == stat_after.st_mtime) + goto ok; /* no modifications */ + + while ((bytes = read(tmp_read, buffer, sizeof(buffer))) > 0) { + do { + ssize_t written = write(STDOUT_FILENO, buffer, bytes); + if (written == -1) { + error("failed to write data to stdout"); + goto err; + } + bytes -= written; + } while (bytes > 0); + } + +ok: + exit_status = EXIT_SUCCESS; +err: + if (tmp_write != -1) + unlink(tempname); + return exit_status; +} diff --git a/bin/dvtm-pager b/bin/dvtm-pager new file mode 100755 index 0000000..975582b --- /dev/null +++ b/bin/dvtm-pager @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ ! -z "$DVTM_PAGER" ]; then + PAGER="$DVTM_PAGER" +elif [ ! -z "$PAGER" ]; then + PAGER="$PAGER" +else + PAGER="less -R" +fi + +exec $PAGER "$@" diff --git a/bin/dvtm-status b/bin/dvtm-status new file mode 100755 index 0000000..f841e3f --- /dev/null +++ b/bin/dvtm-status @@ -0,0 +1,16 @@ +#!/bin/sh + +FIFO="/tmp/dvtm-status.$$" + +[ -p "$FIFO" ] || mkfifo -m 600 "$FIFO" || exit 1 + +while true; do + date +%H:%M + sleep 60 +done > "$FIFO" & + +STATUS_PID=$! +dvtm -s "$FIFO" "$@" 2> /dev/null +kill $STATUS_PID +wait $STATUS_PID 2> /dev/null +rm -f "$FIFO" -- cgit v1.2.1