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
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

@ -91,3 +91,9 @@ int slurp(char *filename, char **bufo, off_t *leno);
#include <stdio.h>
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
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

@ -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;
}

@ -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