From fc6d4a6f69e305627d06955da27b8e8c4c5af6e0 Mon Sep 17 00:00:00 2001 From: Eyal Sawady Date: Tue, 20 Oct 2020 12:55:40 -0400 Subject: [PATCH] Add '|' to pipe page into an external program --- src/gmnlm.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/gmnlm.c b/src/gmnlm.c index d5cb2dc..5d7892b 100644 --- a/src/gmnlm.c +++ b/src/gmnlm.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include "gmni.h" @@ -79,6 +80,7 @@ const char *help_msg = "M\tBrowse bookmarks\n" "r\tReload the page\n" "d \tDownload page to \n" + "|\tPipe page into program\n" "\n" "Other commands include:\n\n" "\tread more lines\n" @@ -309,6 +311,55 @@ has_suffix(char *str, char *suff) return strcmp(&str[strl - suffl], suff) == 0; } +static void +pipe_resp(FILE *out, struct gemini_response resp, char *cmd) { + char buf[BUFSIZ]; + int pfd[2]; + if (pipe(pfd) == -1) { + perror("pipe"); + return; + } + pid_t pid; + switch ((pid = fork())) { + case -1: + perror("fork"); + return; + case 0: + close(pfd[1]); + dup2(pfd[0], STDIN_FILENO); + close(pfd[0]); + execlp("sh", "sh", "-c", cmd); + perror("exec"); + _exit(1); + } + close(pfd[0]); + FILE *f = fdopen(pfd[1], "w"); + // XXX: may affect history, do we care? + for (int n = 1; n > 0;) { + n = BIO_read(resp.bio, buf, BUFSIZ); + if (n == -1) { + fprintf(stderr, "Error: read\n"); + return; + } + ssize_t w = 0; + while (w < (ssize_t)n) { + ssize_t x = fwrite(&buf[w], 1, n - w, f); + if (ferror(f)) { + fprintf(stderr, "Error: write: %s\n", + strerror(errno)); + return; + } + w += x; + } + } + fclose(f); + int status; + waitpid(pid, &status, 0); + if (status != 0) { + fprintf(out, "Command exited %d\n", status); + } +} + static enum gemini_result do_requests(struct browser *browser, struct gemini_response *resp) { @@ -572,6 +623,19 @@ do_prompts(const char *prompt, struct browser *browser) gemini_response_finish(&resp); result = PROMPT_AGAIN; goto exit; + case '|': + strncpy(&url[0], browser->plain_url, sizeof(url)); + res = do_requests(browser, &resp); + if (res != GEMINI_OK) { + fprintf(stderr, "Error: %s\n", + gemini_strerr(res, &resp)); + goto exit; + } + pipe_resp(browser->tty, resp, &in[1]); + gemini_response_finish(&resp); + set_url(browser, url, NULL); + result = PROMPT_AGAIN; + goto exit; case '?': if (in[1]) break; fprintf(browser->tty, "%s", help_msg);