/* 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 . */ #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 &= ~0u ^ 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 #ifndef USE_RAWTERM UNUSEDP #endif ) { 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) { int c = fgetc(opentty(1)); if(c < 0) /* Treat end-of-file or error as no */ ans[0] = 'n'; else ans[0] = (char) c; 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; } }