From 77777d4c0d497b2cac51825425cf444e10d5ade5 Mon Sep 17 00:00:00 2001
From: Chris Allegretta <chrisa@asty.org>
Date: Fri, 29 Mar 2002 16:31:29 +0000
Subject: [PATCH] Add David Benbennick's changes to open_pipe() and move it to
 nano.c, and add his nperror function

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1159 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
---
 ChangeLog |   9 +++--
 files.c   |  51 ++------------------------
 nano.c    | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 proto.h   |   3 ++
 utils.c   |  13 +++++++
 5 files changed, 129 insertions(+), 52 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 540ea9f4..edbcf316 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,9 +3,10 @@ CVS code -
 	- Type misalignments and mem leaks in renumber_all, do_justify
 	  and do_spell (Rocco & Steven Kneizys).
 	- New "External Command" code, originally by Dwayne Rightler,
-	  Chris & Rocco. New function files.c:open_pipe(), changes to
-	  do_insertfile(), new list extcmd_list, cmd is ^X after ^R by
-	  default.
+	  various fixes and changes by Chris, Rocco and David Benbennick. 
+	  New function nano.c:open_pipe() and signal handler cancel_fork(), 
+	  changes to do_insertfile(), new list extcmd_list, cmd is 
+	  ^X after ^R.
 	- Added separate regex variable (color_regex and colormatches)
 	  so that color syntax and regex search/replace can coexist.
 - files.c:
@@ -50,6 +51,8 @@ CVS code -
 - utils.c:
   stristr() 
 	- Defined regardless of NANO_SMALL (noticed by Jordi).
+  nperror()
+	- New wrapper for perror (David Benbennick).
 - winio.c:
   do_credits()
 	- Add Thomas Dickey.
diff --git a/files.c b/files.c
index 0df7b24d..5a9a7238 100644
--- a/files.c
+++ b/files.c
@@ -110,12 +110,8 @@ int read_byte(int fd, char *filename, char *input)
 	index = 0;
 	size = read(fd, buf, BUFSIZ);
 	if (size == -1) {
-	    clear();
-	    refresh();
-	    resetty();
-	    endwin();
-	    perror(filename);
-	    total_refresh();
+	    size = index;	/* note index==0 */
+	    nperror(filename);
 	    return -1;
 	}
 	if (!size)
@@ -292,49 +288,6 @@ int read_file(int fd, char *filename, int quiet)
     return 1;
 }
 
-#ifndef NANO_SMALL
-int open_pipe(char *command)
-{
-    int fd[2], pid;
-    int fork_status;
-  
-  /* Make our pipes. */
-
-    if (pipe(fd) == -1) {
-	statusbar(_("Could not pipe"));
-	return 1;
-    }
-
-    /* Fork a child */
-
-    if ((pid = fork()) == 0) {
-	close(fd[0]);
-	dup2(fd[1], fileno(stdout));
-	dup2(fd[1], fileno(stderr));
-	/* If execl() returns at all, there was an error. */
-      
-	execl("/bin/sh","sh","-c",command,0);
-	exit(0);
-    }
-
-    /* Else continue as parent */
-
-    close(fd[1]);
-
-    if (pid == -1) {
-	close(fd[0]);
-	statusbar(_("Could not fork"));
-	return 1;
-    }
-
-    read_file(fd[0],"stdin",0);
-    set_modified();
-
-    wait(&fork_status);
-
-    return 0;
-}
-#endif /* NANO_SMALL */
 
 /* Open the file (and decide if it exists) */
 int open_file(char *filename, int insert, int quiet)
diff --git a/nano.c b/nano.c
index cfb666f3..bb75156f 100644
--- a/nano.c
+++ b/nano.c
@@ -1733,6 +1733,111 @@ int do_spell(void)
 #endif
 }
 
+#ifndef NANO_SMALL
+static int pid;		/* this is the PID of the newly forked process below.  
+			 * It must be global since the signal handler needs it.
+			 */
+
+RETSIGTYPE cancel_fork(int signal) {
+    if (kill(pid, SIGKILL)==-1) nperror("kill");
+}
+
+int open_pipe(char *command)
+{
+    int fd[2];
+    struct sigaction oldaction, newaction;
+			/* original and temporary handlers for SIGINT */
+#ifdef _POSIX_VDISABLE
+    struct termios term, newterm;
+#endif   /* _POSIX_VDISABLE */
+    int cancel_sigs = 0;
+    /* cancel_sigs==1 means that sigaction failed without changing the 
+     * signal handlers.  cancel_sigs==2 means the signal handler was
+     * changed, but the tcsetattr didn't succeed.
+     * I use this variable since it is important to put things back when
+     * we finish, even if we get errors.
+     */
+
+  /* Make our pipes. */
+
+    if (pipe(fd) == -1) {
+	statusbar(_("Could not pipe"));
+	return 1;
+    }
+
+    /* Fork a child */
+
+    if ((pid = fork()) == 0) {
+	close(fd[0]);
+	dup2(fd[1], fileno(stdout));
+	dup2(fd[1], fileno(stderr));
+	/* If execl() returns at all, there was an error. */
+      
+	execl("/bin/sh","sh","-c",command,0);
+	exit(0);
+    }
+
+    /* Else continue as parent */
+
+    close(fd[1]);
+
+    if (pid == -1) {
+	close(fd[0]);
+	statusbar(_("Could not fork"));
+	return 1;
+    }
+
+    /* before we start reading the forked command's output, we set 
+     * things up so that ^C will cancel the new process.
+     */
+    if (sigaction(SIGINT, NULL, &newaction)==-1) {
+	cancel_sigs = 1;
+	nperror("sigaction");
+    } else {
+	newaction.sa_handler = cancel_fork;
+	if (sigaction(SIGINT, &newaction, &oldaction)==-1) {
+	    cancel_sigs = 1;
+	    nperror("sigaction");
+	}
+    }
+    /* note that now oldaction is the previous SIGINT signal handler, to 
+       be restored later */
+
+    /* if the platform supports disabling individual control characters */
+#ifdef _POSIX_VDISABLE
+    if (!cancel_sigs && tcgetattr(0, &term) == -1) {
+	cancel_sigs = 2;
+	nperror("tcgetattr");
+    }
+    if (!cancel_sigs) {
+	newterm = term;
+	/* Grab oldterm's VINTR key :-) */
+	newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
+	if (tcsetattr(0, TCSANOW, &newterm) == -1) {
+	    cancel_sigs = 2;
+	    nperror("tcsetattr");
+	}
+    }
+#endif   /* _POSIX_VDISABLE */
+
+    read_file(fd[0],"stdin",0);
+    set_modified();
+
+    if (wait(NULL) == -1) 
+	nperror("wait");
+
+#ifdef _POSIX_VDISABLE
+    if (!cancel_sigs && tcsetattr(0, TCSANOW, &term) == -1)
+	nperror("tcsetattr");
+#endif   /* _POSIX_VDISABLE */
+
+    if (cancel_sigs!=1 && sigaction(SIGINT, &oldaction, NULL) == -1)
+	nperror("sigaction");
+
+    return 0;
+}
+#endif /* NANO_SMALL */
+
 int do_exit(void)
 {
     int i;
diff --git a/proto.h b/proto.h
index 8a158be7..945aa86b 100644
--- a/proto.h
+++ b/proto.h
@@ -116,6 +116,8 @@ int open_file(char *filename, int insert, int quiet);
 int do_insertfile(int loading_file);
 int length_of_list(shortcut *s);
 int num_of_digits(int n);
+int open_pipe(char *command);
+int read_file(int fd, char *filename, int quiet);
 
 #ifdef ENABLE_MULTIBUFFER
 int add_open_file(int update);
@@ -171,6 +173,7 @@ void center_cursor(void);
 void bottombars(shortcut *s);
 void blank_statusbar_refresh(void);
 void *nmalloc (size_t howmuch);
+void nperror(const char *s);
 void *mallocstrcpy(char *dest, char *src);
 void wrap_reset(void);
 void display_main_list(void);
diff --git a/utils.c b/utils.c
index 826c86a4..aa9dc25c 100644
--- a/utils.c
+++ b/utils.c
@@ -21,6 +21,7 @@
 
 #include "config.h"
 
+#include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
@@ -160,6 +161,18 @@ char *strstrwrapper(char *haystack, char *needle, char *rev_start)
 #endif
 }
 
+/* This is a wrapper for the perror function.  The wrapper takes care of 
+ * ncurses, calls perror (which writes to STDERR), then refreshes the 
+ * screen.  Note that nperror causes the window to flicker once.
+ */
+void nperror(const char *s) {
+	/* leave ncurses mode, go to the terminal */
+    if (endwin() != ERR) {
+	perror(s);		/* print the error */
+	total_refresh();	/* return to ncurses and repaint */
+    }
+}
+
 /* Thanks BG, many ppl have been asking for this... */
 void *nmalloc(size_t howmuch)
 {
-- 
GitLab