| /* 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 |
| #ifdef future |
| #define FAIL (-1) |
| #endif |
| #define DONE 0 |
| static Terminal in_orig; |
| |
| /*--------------- Signal Handler routines -------------*/ |
| |
| static void tty_time_out(int dummy UNUSEDP) NORETURN; |
| static void tty_time_out(int dummy UNUSEDP) |
| { |
| 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; |
| } |
| } |