summaryrefslogtreecommitdiff
path: root/tty.c
diff options
context:
space:
mode:
Diffstat (limited to 'tty.c')
-rw-r--r--tty.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/tty.c b/tty.c
new file mode 100644
index 0000000..25950f2
--- /dev/null
+++ b/tty.c
@@ -0,0 +1,222 @@
+/* Copyright 1997,2001,2002,2007-2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include "sysincludes.h"
+#include "mtools.h"
+
+static FILE *tty=NULL;
+static int notty=0;
+static int ttyfd=-1;
+#ifdef USE_RAWTERM
+int mtools_raw_tty = 1;
+#else
+int mtools_raw_tty = 0;
+#endif
+
+#ifdef USE_RAWTERM
+# if defined TCSANOW && defined HAVE_TCSETATTR
+/* we have tcsetattr & tcgetattr. Good */
+typedef struct termios Terminal;
+# define stty(a,b) (void)tcsetattr(a,TCSANOW,b)
+# define gtty(a,b) (void)tcgetattr(a,b)
+# define USE_TCIFLUSH
+
+# elif defined TCSETS && defined TCGETS
+typedef struct termios Terminal;
+# define stty(a,b) (void)ioctl(a,TCSETS,(char *)b)
+# define gtty(a,b) (void)ioctl(a,TCGETS,(char *)b)
+# define USE_TCIFLUSH
+
+# elif defined TCSETA && defined TCGETA
+typedef struct termio Terminal;
+# define stty(a,b) (void)ioctl(a,TCSETA,(char *)b)
+# define gtty(a,b) (void)ioctl(a,TCGETA,(char *)b)
+# define USE_TCIFLUSH
+
+# elif defined(HAVE_SGTTY_H) && defined(TIOCSETP) && defined(TIOCGETP)
+typedef struct sgttyb Terminal;
+# define stty(a,b) (void)ioctl(a,TIOCSETP,(char *)b)
+# define gtty(a,b) (void)ioctl(a,TIOCGETP,(char *)b)
+# define USE_SGTTY
+# define discard_input(a) /**/
+
+# else
+/* no way to use raw terminal */
+# warning Cannot use raw terminal code (disabled)
+# undef USE_RAWTERM
+# endif
+
+#endif
+
+#ifdef USE_TCIFLUSH
+# if defined TCIFLUSH && defined HAVE_TCFLUSH
+# define discard_input(a) tcflush(a,TCIFLUSH)
+# else
+# define discard_input(a) /**/
+# endif
+#endif
+
+#ifdef USE_RAWTERM
+
+static int tty_mode = -1; /* 1 for raw, 0 for cooked, -1 for initial */
+static int need_tty_reset = 0;
+static int handlerIsSet = 0;
+
+#define restore_tty(a) stty(STDIN,a)
+
+
+#define STDIN ttyfd
+#define FAIL (-1)
+#define DONE 0
+static Terminal in_orig;
+
+/*--------------- Signal Handler routines -------------*/
+
+static void tty_time_out(int dummy)
+{
+ int exit_code;
+ signal(SIGALRM, SIG_IGN);
+ if(tty && need_tty_reset)
+ restore_tty (&in_orig);
+#ifdef future
+ if (fail_on_timeout)
+ exit_code=SHFAIL;
+ else {
+ if (default_choice && mode_defined) {
+ if (yes_no) {
+ if ('Y' == default_choice)
+ exit_code=0;
+ else
+ exit_code=1;
+ } else
+ exit_code=default_choice-minc+1;
+ } else
+ exit_code=DONE;
+ }
+#else
+ exit_code = DONE;
+#endif
+ exit(exit_code);
+}
+
+static void cleanup_tty(void)
+{
+ if(tty && need_tty_reset) {
+ restore_tty (&in_orig);
+ setup_signal();
+ }
+}
+
+static void set_raw_tty(int mode)
+{
+ Terminal in_raw;
+
+ if(mode != tty_mode && mode != -1) {
+ if(!handlerIsSet) {
+ /* Determine existing TTY settings */
+ gtty (STDIN, &in_orig);
+ need_tty_reset = 1;
+
+ /* Restore original TTY settings on exit */
+ atexit(cleanup_tty);
+ handlerIsSet = 1;
+ }
+
+
+ setup_signal();
+ signal (SIGALRM, tty_time_out);
+
+ /* Change STDIN settings to raw */
+
+ gtty (STDIN, &in_raw);
+ if(mode) {
+#ifdef USE_SGTTY
+ in_raw.sg_flags |= CBREAK;
+#else
+ in_raw.c_lflag &= ~ICANON;
+ in_raw.c_cc[VMIN]=1;
+ in_raw.c_cc[VTIME]=0;
+#endif
+ stty (STDIN, &in_raw);
+ } else {
+#ifdef USE_SGTTY
+ in_raw.sg_flags &= ~CBREAK;
+#else
+ in_raw.c_lflag |= ICANON;
+#endif
+ stty (STDIN, &in_raw);
+ }
+ tty_mode = mode;
+ discard_input(STDIN);
+ }
+}
+#endif
+
+FILE *opentty(int mode)
+{
+ if(notty)
+ return NULL;
+ if (tty == NULL) {
+ ttyfd = open("/dev/tty", O_RDONLY);
+ if(ttyfd >= 0) {
+ tty = fdopen(ttyfd, "r");
+ }
+ }
+ if (tty == NULL){
+ if ( !isatty(0) ){
+ notty = 1;
+ return NULL;
+ }
+ ttyfd = 0;
+ tty = stdin;
+ }
+#ifdef USE_RAWTERM
+ if(mtools_raw_tty)
+ set_raw_tty(mode);
+#endif
+ return tty;
+}
+
+int ask_confirmation(const char *format, ...)
+{
+ char ans[10];
+ va_list ap;
+
+ if(!opentty(-1))
+ return 0;
+
+ while (1) {
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ fflush(stderr);
+ fflush(opentty(-1));
+ if (mtools_raw_tty) {
+ ans[0] = fgetc(opentty(1));
+ fputs("\n", stderr);
+ } else {
+ if(fgets(ans,9, opentty(0)) == NULL)
+ /* Treat end-of-file as no */
+ ans[0] = 'n';
+ }
+ if (ans[0] == 'y' || ans[0] == 'Y')
+ return 0;
+ if (ans[0] == 'n' || ans[0] == 'N')
+ return -1;
+ }
+}