mshow: spawn a pager for interactive use

pull/22/merge
Leah Neukirchen 7 years ago
parent e7ce5ecc78
commit e8107b1889

@ -24,7 +24,7 @@ maddr magrep mexport mflag mgenmid mhdr mlist mpick mscan msed mseq mshow msort
mthread : seq.o slurp.o mthread : seq.o slurp.o
maddr magrep mhdr mpick mscan mshow : rfc2047.o maddr magrep mhdr mpick mscan mshow : rfc2047.o
magrep mshow : rfc2045.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 msort : mystrverscmp.o
mmime : slurp.o mmime : slurp.o

@ -91,3 +91,9 @@ int slurp(char *filename, char **bufo, off_t *leno);
#include <stdio.h> #include <stdio.h>
void safe_u8putstr(char *s0, size_t l, FILE *stream); void safe_u8putstr(char *s0, size_t l, FILE *stream);
// pipeto.c
pid_t pipeto(const char *cmdline);
int pipeclose(pid_t pid);

@ -30,7 +30,7 @@ See
.Xr mmsg 7 .Xr mmsg 7
for the message argument syntax. for the message argument syntax.
If used interactively and no messages are given, If used interactively and no messages are given,
displays the current message. displays the current message using colorization and a pager.
.Pp .Pp
The options are as follows: The options are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
@ -118,6 +118,21 @@ The environment variable
.Ev PIPE_CHARSET .Ev PIPE_CHARSET
will be set to the charset declared in the MIME part, will be set to the charset declared in the MIME part,
if known. 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 .Sh EXIT STATUS
.Ex -std .Ex -std
.Sh SEE ALSO .Sh SEE ALSO

@ -703,6 +703,8 @@ done:
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
pid_t pid1 = -1, pid2 = -1;
int c; int c;
while ((c = getopt(argc, argv, "h:A:qrtHLx:O:Rn")) != -1) while ((c = getopt(argc, argv, "h:A:qrtHLx:O:Rn")) != -1)
switch(c) { switch(c) {
@ -731,6 +733,22 @@ main(int argc, char *argv[])
if (!rflag && !Oflag && !Rflag) if (!rflag && !Oflag && !Rflag)
safe_output = 1; 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 if (xflag) { // extract
extract(xflag, argc-optind, argv+optind, 0); extract(xflag, argc-optind, argv+optind, 0);
} else if (Oflag) { // extract to stdout } else if (Oflag) { // extract to stdout
@ -758,5 +776,10 @@ main(int argc, char *argv[])
blaze822_seq_setcur(newcur); blaze822_seq_setcur(newcur);
} }
if (pid2 > 0)
pipeclose(pid2);
if (pid1 > 0)
pipeclose(pid1);
return 0; return 0;
} }

@ -0,0 +1,98 @@
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
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;
}
Loading…
Cancel
Save