summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2017-05-23 15:16:27 +0200
committerLeah Neukirchen <leah@vuxu.org>2017-05-23 15:16:27 +0200
commite8107b1889a620b6ba446953e698b30f1803b2cb (patch)
tree762870878b73df56171da14d0cec1f74a64ee0a8
parente7ce5ecc78dc8c56f32cd839369066cf33997305 (diff)
downloadmblaze-e8107b1889a620b6ba446953e698b30f1803b2cb.tar.gz
mblaze-e8107b1889a620b6ba446953e698b30f1803b2cb.tar.xz
mblaze-e8107b1889a620b6ba446953e698b30f1803b2cb.zip
mshow: spawn a pager for interactive use
-rw-r--r--Makefile2
-rw-r--r--blaze822.h6
-rw-r--r--man/mshow.117
-rw-r--r--mshow.c23
-rw-r--r--pipeto.c98
5 files changed, 144 insertions, 2 deletions
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 <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);
+
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 <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;
+}