[RFC] new feature: exit with an error status of 2 for ^X^Q and for ^O^Q

Benno Schulenberg <[email protected]> Sat, 3 May 2025 12:24:07 +0200
Newsgroups gmane.editors.nano.devel
Message-ID <[email protected]>
Normally, nano exits with a status of 0.  But if the user wants to
make nano exit with an error status (to signal failure to a calling
program), they can now use ^X^Q (when the buffer is modified), or
^O^Q (when option --saveonexit is in effect).

This fulfills https://savannah.gnu.org/bugs/?65755.
---
 src/files.c      | 1 +
 src/global.c     | 3 +++
 src/nano.c       | 3 ++-
 src/prompt.c     | 6 ++++--
 src/prototypes.h | 2 ++
 5 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/files.c b/src/files.c
index 1d74e18c..32d3092e 100644
--- a/src/files.c
+++ b/src/files.c
@@ -2195,6 +2195,7 @@ int write_it_out(bool exiting, bool withprompt)
 
 		/* Upon request, abandon the buffer. */
 		if (function == discard_buffer) {
+			final_status = 2;  /* ^O^Q makes nano exit with an error. */
 			free(given);
 			return 2;
 		}
diff --git a/src/global.c b/src/global.c
index 007bba90..eb3be913 100644
--- a/src/global.c
+++ b/src/global.c
@@ -58,6 +58,9 @@ char *foretext = NULL;
 		/* What was typed at the Execute prompt before invoking a tool. */
 #endif
 
+int final_status = 0;
+		/* The status value that nano returns upon exit. */
+
 bool inhelp = FALSE;
 		/* Whether we are in the help viewer. */
 char *title = NULL;
diff --git a/src/nano.c b/src/nano.c
index f61db14e..57beaf78 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -260,7 +260,7 @@ void finish(void)
 #endif
 
 	/* Get out. */
-	exit(0);
+	exit(final_status);
 }
 
 /* Close the current buffer, and terminate nano if it is the only buffer. */
@@ -2717,6 +2717,7 @@ int main(int argc, char **argv)
 			wredrawln(midwin, editwinrows - 1, 1);
 #endif
 
+		final_status = 0;
 		errno = 0;
 		focusing = TRUE;
 
diff --git a/src/prompt.c b/src/prompt.c
index be006b90..c7909bba 100644
--- a/src/prompt.c
+++ b/src/prompt.c
@@ -788,10 +788,12 @@ int ask_user(bool withall, const char *question)
 #endif
 		/* Interpret ^N as "No", to allow exiting in anger, and ^Q or ^X too. */
 		else if (kbinput == '\x0E' || (kbinput == '\x11' && !ISSET(MODERN_BINDINGS)) ||
-									  (kbinput == '\x18' && ISSET(MODERN_BINDINGS)))
+									  (kbinput == '\x18' && ISSET(MODERN_BINDINGS))) {
 			choice = NO;
+			if (kbinput != '\x0E')  /* ^X^Q makes nano exit with an error. */
+				final_status = 2;
 		/* Also, interpret ^Y as "Yes, and  ^A as "All". */
-		else if (kbinput == '\x19')
+		} else if (kbinput == '\x19')
 			choice = YES;
 		else if (kbinput == '\x01' && withall)
 			choice = ALL;
diff --git a/src/prototypes.h b/src/prototypes.h
index ceca2c23..fcc59dd5 100644
--- a/src/prototypes.h
+++ b/src/prototypes.h
@@ -40,6 +40,8 @@ extern bool report_size;
 extern bool ran_a_tool;
 extern char *foretext;
 
+extern int final_status;
+
 extern bool inhelp;
 extern char *title;
 
-- 
2.48.1