From f86e181803949a3d223d0c94e0f3bc2f1db04c9c Mon Sep 17 00:00:00 2001
From: Benno Schulenberg <bensberg@telfort.nl>
Date: Thu, 8 Oct 2020 19:51:51 +0200
Subject: [PATCH] possible new feature: allow piping out the buffer via
 standard output

This can be used to decode a file, edit it, and then recode it without
writing the decoded data to disk:

	gpg --decrypt encodedtext.gpg | src/nano - |
			gpg --symmetric >theeditedtext.gpg
	mv theeditedtext.gpg encodedtext.gpg

(One would need to ensure that nano's memory doesn't get swapped out to
disk.  Is there a way to do that, other than disabling swap entirely?)
---
 src/files.c      | 14 +++++++++++---
 src/global.c     |  3 +++
 src/nano.c       | 20 ++++++++++++++++++++
 src/prototypes.h |  2 ++
 4 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/src/files.c b/src/files.c
index dc1715d1..d3b09732 100644
--- a/src/files.c
+++ b/src/files.c
@@ -1739,14 +1739,14 @@ bool write_file(const char *name, FILE *thefile, bool tmp,
 #ifdef ENABLE_OPERATINGDIR
 	/* If we're writing a temporary file, we're probably going outside
 	 * the operating directory, so skip the operating directory test. */
-	if (!tmp && outside_of_confinement(realname, FALSE)) {
+	if (!tmp && !outpipe && outside_of_confinement(realname, FALSE)) {
 		statusline(ALERT, _("Can't write outside of %s"), operating_dir);
 		goto cleanup_and_exit;
 	}
 #endif
 #ifndef NANO_TINY
 	/* Check whether the file (at the end of the symlink) exists. */
-	is_existing_file = (!tmp) && (stat(realname, &st) != -1);
+	is_existing_file = !tmp && !outpipe && (stat(realname, &st) != -1);
 
 	/* If we haven't statted this file before (say, the user just specified
 	 * it interactively), stat and save the value now, or else we will chase
@@ -1806,6 +1806,7 @@ bool write_file(const char *name, FILE *thefile, bool tmp,
 		mode_t permissions = (tmp ? S_IRUSR|S_IWUSR : RW_FOR_ALL);
 		int fd;
 
+		if (!outpipe) {
 #ifndef NANO_TINY
 		block_sigwinch(TRUE);
 		install_handler_for_Ctrl_C();
@@ -1832,6 +1833,8 @@ bool write_file(const char *name, FILE *thefile, bool tmp,
 #endif
 			goto cleanup_and_exit;
 		}
+		} else
+			fd = outpipe;
 
 		thefile = fdopen(fd, (method == APPEND) ? "ab" : "wb");
 
@@ -1922,7 +1925,7 @@ bool write_file(const char *name, FILE *thefile, bool tmp,
 #endif
 
 	/* Ensure the data has reached the disk before reporting it as written. */
-	if (fflush(thefile) != 0 || fsync(fileno(thefile)) != 0) {
+	if (!outpipe && (fflush(thefile) != 0 || fsync(fileno(thefile)) != 0)) {
 		statusline(ALERT, _("Error writing %s: %s"), realname, strerror(errno));
 		fclose(thefile);
 		goto cleanup_and_exit;
@@ -2056,6 +2059,11 @@ int do_writeout(bool exiting, bool withprompt)
 	as_an_at = FALSE;
 
 #ifndef NANO_TINY
+	if (outpipe) {
+		write_file("", NULL, FALSE, method, TRUE);
+		finish();
+	}
+
 	given = copy_of((openfile->mark && !exiting) ? "" : openfile->filename);
 #else
 	given = copy_of(openfile->filename);
diff --git a/src/global.c b/src/global.c
index 4ac66590..b17426e0 100644
--- a/src/global.c
+++ b/src/global.c
@@ -31,6 +31,9 @@ volatile sig_atomic_t the_window_resized = FALSE;
 		/* Set to TRUE by the handler whenever a SIGWINCH occurs. */
 #endif
 
+int outpipe = 0;
+		/* Becomes nonzero when nano's output is connected to a pipe. */
+
 bool on_a_vt = FALSE;
 		/* Whether we're running on a Linux console (a VT). */
 bool shifted_metas = FALSE;
diff --git a/src/nano.c b/src/nano.c
index 787f5e4b..241dc485 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -1797,6 +1797,24 @@ int main(int argc, char **argv)
 		{NULL, 0, NULL, 0}
 	};
 
+#ifndef NANO_TINY
+	/* When standard output is not a terminal, then clone its file descriptor
+	 * to a new one (to be used for writing the buffer) and reconnect standard
+	 * output to the terminal so that we can use the screen for editing. */
+	if (!isatty(fileno(stdout))) {
+		int thetty = open("/dev/tty", O_WRONLY);
+
+		if (thetty < 1)
+			die(_("Could not reconnect stdout to terminal\n"));
+
+		outpipe = dup(fileno(stdout));
+		SET(SAVE_ON_EXIT);
+
+		dup2(thetty, fileno(stdout));
+		close(thetty);
+	}
+#endif
+
 #ifdef __linux__
 	struct vt_stat dummy;
 
@@ -2515,6 +2533,8 @@ int main(int argc, char **argv)
 #ifdef ENABLE_MULTIBUFFER
 	else {
 		openfile = openfile->next;
+		if (outpipe && more_than_one)
+			die(_("When piping, just one input file is allowed\n"));
 		if (more_than_one)
 			mention_name_and_linecount();
 		if (ISSET(VIEW_MODE))
diff --git a/src/prototypes.h b/src/prototypes.h
index d1b2ece6..288fc9e8 100644
--- a/src/prototypes.h
+++ b/src/prototypes.h
@@ -26,6 +26,8 @@
 extern volatile sig_atomic_t the_window_resized;
 #endif
 
+extern int outpipe;
+
 extern bool on_a_vt;
 extern bool shifted_metas;
 
-- 
2.25.4

