From e8107b1889a620b6ba446953e698b30f1803b2cb Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Tue, 23 May 2017 15:16:27 +0200 Subject: mshow: spawn a pager for interactive use --- Makefile | 2 +- blaze822.h | 6 ++++ man/mshow.1 | 17 ++++++++++- mshow.c | 23 +++++++++++++++ pipeto.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 pipeto.c diff --git a/Makefile b/Makefile index bb21265..dc9f33e 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ maddr magrep mexport mflag mgenmid mhdr mlist mpick mscan msed mseq mshow msort mthread : seq.o slurp.o maddr magrep mhdr mpick mscan mshow : rfc2047.o magrep mshow : rfc2045.o -mshow : filter.o safe_u8putstr.o rfc2231.o +mshow : filter.o safe_u8putstr.o rfc2231.o pipeto.o msort : mystrverscmp.o mmime : slurp.o diff --git a/blaze822.h b/blaze822.h index 4dfd8f5..a5cb008 100644 --- a/blaze822.h +++ b/blaze822.h @@ -91,3 +91,9 @@ int slurp(char *filename, char **bufo, off_t *leno); #include void safe_u8putstr(char *s0, size_t l, FILE *stream); + +// pipeto.c + +pid_t pipeto(const char *cmdline); +int pipeclose(pid_t pid); + diff --git a/man/mshow.1 b/man/mshow.1 index acce690..66c839b 100644 --- a/man/mshow.1 +++ b/man/mshow.1 @@ -30,7 +30,7 @@ See .Xr mmsg 7 for the message argument syntax. If used interactively and no messages are given, -displays the current message. +displays the current message using colorization and a pager. .Pp The options are as follows: .Bl -tag -width Ds @@ -118,6 +118,21 @@ The environment variable .Ev PIPE_CHARSET will be set to the charset declared in the MIME part, if known. +.Sh ENVIRONMENT +.Bl -tag -width MBLAZE_NOCOLOR +.It Ev MBLAZE_PAGER +Any non-empty value of the environment variable +.Ev MBLAZE_PAGER +is used instead of the standard pagination program, specified in +.Ev PAGER . +When empty or set to +.Sq Ic cat , +no pager is spawned. +.It Ev MBLAZE_NOCOLOR +If non-empty, +.Nm +will not spawn a colorization filter. +.El .Sh EXIT STATUS .Ex -std .Sh SEE ALSO diff --git a/mshow.c b/mshow.c index 4c62410..a96d540 100644 --- a/mshow.c +++ b/mshow.c @@ -703,6 +703,8 @@ done: int main(int argc, char *argv[]) { + pid_t pid1 = -1, pid2 = -1; + int c; while ((c = getopt(argc, argv, "h:A:qrtHLx:O:Rn")) != -1) switch(c) { @@ -731,6 +733,22 @@ main(int argc, char *argv[]) if (!rflag && !Oflag && !Rflag) safe_output = 1; + if (safe_output && isatty(1)) { + char *pg; + pg = getenv("MBLAZE_PAGER"); + if (!pg) + pg = getenv("PAGER"); + if (pg && *pg && strcmp(pg, "cat") != 0) { + pid2 = pipeto(pg); + if (pid2 < 0) + fprintf(stderr, + "mshow: spawning pager '%s': %s\n", + pg, strerror(errno)); + else if (!getenv("MBLAZE_NOCOLOR")) + pid1 = pipeto("mcolor"); // ignore error + } + } + if (xflag) { // extract extract(xflag, argc-optind, argv+optind, 0); } else if (Oflag) { // extract to stdout @@ -758,5 +776,10 @@ main(int argc, char *argv[]) blaze822_seq_setcur(newcur); } + if (pid2 > 0) + pipeclose(pid2); + if (pid1 > 0) + pipeclose(pid1); + return 0; } diff --git a/pipeto.c b/pipeto.c new file mode 100644 index 0000000..77982e1 --- /dev/null +++ b/pipeto.c @@ -0,0 +1,98 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +pid_t +pipeto(const char *cmdline) +{ + int pipe0[2]; // stdout -> stdin + int pipe1[2]; // child errno -> parent + pid_t pid; + + if (pipe(pipe0) < 0) + return -1; + if (pipe(pipe1) < 0) + return -1; + + pid = fork(); + if (pid < 0) { + return -1; + } else if (pid == 0) { // in child + close(pipe1[0]); + // close errno pipe on successful exec + fcntl(pipe1[1], F_SETFD, FD_CLOEXEC); + + if (dup2(pipe0[0], 0) < 0) + exit(111); + + close(pipe0[0]); + close(pipe0[1]); + + // split cmdline, just on spaces + char *argv[16]; + int argc = 0; + char *cp = strdup(cmdline); + if (!cp) + exit(111); + while (argc < 16 && *cp) { + argv[argc++] = cp; + cp = strchr(cp, ' '); + if (!cp) + break; + *cp++ = 0; + while (*cp == ' ') + cp++; + } + argv[argc] = 0; + + execvp(argv[0], argv); + + // execvp failed, write errno to parent + long e = errno; + if (write(pipe1[1], &e, sizeof e) < 0) + exit(111); // do a magic dance for gcc -Wunused-result + exit(111); + } else { // in parent + close(pipe1[1]); + + long e; + ssize_t n = read(pipe1[0], &e, sizeof e); + if (n < 0) + e = errno; + close(pipe1[0]); + + if (n == 0) { + // child executed successfully, redirect stdout to it + if (dup2(pipe0[1], 1) < 0) + return -1; + + close(pipe0[0]); + close(pipe0[1]); + + return pid; + } else { + errno = e; + return -1; + } + } + +// return pid; +} + +int +pipeclose(pid_t pid) +{ + int s; + + fflush(0); + close(1); + waitpid(pid, &s, 0); + + return s; +} -- cgit 1.4.1