• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*  Copyright 1997,2001,2002,2007-2009 Alain Knaff.
2  *  This file is part of mtools.
3  *
4  *  Mtools is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Mtools is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "sysincludes.h"
19 #include "mtools.h"
20 
21 static FILE *tty=NULL;
22 static int notty=0;
23 static int ttyfd=-1;
24 #ifdef USE_RAWTERM
25 int	mtools_raw_tty = 1;
26 #else
27 int	mtools_raw_tty = 0;
28 #endif
29 
30 #ifdef USE_RAWTERM
31 # if defined TCSANOW && defined HAVE_TCSETATTR
32 /* we have tcsetattr & tcgetattr. Good */
33 typedef struct termios Terminal;
34 #  define stty(a,b)        (void)tcsetattr(a,TCSANOW,b)
35 #  define gtty(a,b)        (void)tcgetattr(a,b)
36 #  define USE_TCIFLUSH
37 
38 # elif defined TCSETS && defined TCGETS
39 typedef struct termios Terminal;
40 #  define stty(a,b) (void)ioctl(a,TCSETS,(char *)b)
41 #  define gtty(a,b) (void)ioctl(a,TCGETS,(char *)b)
42 #  define USE_TCIFLUSH
43 
44 # elif defined TCSETA && defined TCGETA
45 typedef struct termio Terminal;
46 #  define stty(a,b) (void)ioctl(a,TCSETA,(char *)b)
47 #  define gtty(a,b) (void)ioctl(a,TCGETA,(char *)b)
48 #  define USE_TCIFLUSH
49 
50 # elif defined(HAVE_SGTTY_H) && defined(TIOCSETP) && defined(TIOCGETP)
51 typedef struct sgttyb Terminal;
52 #  define stty(a,b) (void)ioctl(a,TIOCSETP,(char *)b)
53 #  define gtty(a,b) (void)ioctl(a,TIOCGETP,(char *)b)
54 #  define USE_SGTTY
55 #  define discard_input(a) /**/
56 
57 # else
58 /* no way to use raw terminal */
59 #  warning Cannot use raw terminal code (disabled)
60 #  undef USE_RAWTERM
61 # endif
62 
63 #endif
64 
65 #ifdef USE_TCIFLUSH
66 # if defined TCIFLUSH && defined HAVE_TCFLUSH
67 #  define discard_input(a) tcflush(a,TCIFLUSH)
68 # else
69 #  define discard_input(a) /**/
70 # endif
71 #endif
72 
73 #ifdef USE_RAWTERM
74 
75 static int tty_mode = -1; /* 1 for raw, 0 for cooked, -1 for initial */
76 static int need_tty_reset = 0;
77 static int handlerIsSet = 0;
78 
79 #define restore_tty(a) stty(STDIN,a)
80 
81 
82 #define STDIN ttyfd
83 #ifdef future
84 #define FAIL (-1)
85 #endif
86 #define DONE 0
87 static Terminal in_orig;
88 
89 /*--------------- Signal Handler routines -------------*/
90 
91 static void tty_time_out(int dummy UNUSEDP) NORETURN;
tty_time_out(int dummy UNUSEDP)92 static void tty_time_out(int dummy UNUSEDP)
93 {
94 	int exit_code;
95 	signal(SIGALRM, SIG_IGN);
96 	if(tty && need_tty_reset)
97 		restore_tty (&in_orig);
98 #ifdef future
99 	if (fail_on_timeout)
100 		exit_code=SHFAIL;
101 	else {
102 		if (default_choice && mode_defined) {
103 			if (yes_no) {
104 				if ('Y' == default_choice)
105 					exit_code=0;
106 				else
107 					exit_code=1;
108 			} else
109 				exit_code=default_choice-minc+1;
110 		} else
111 			exit_code=DONE;
112 	}
113 #else
114 	exit_code = DONE;
115 #endif
116 	exit(exit_code);
117 }
118 
cleanup_tty(void)119 static void cleanup_tty(void)
120 {
121 	if(tty && need_tty_reset) {
122 		restore_tty (&in_orig);
123 		setup_signal();
124 	}
125 }
126 
set_raw_tty(int mode)127 static void set_raw_tty(int mode)
128 {
129 	Terminal in_raw;
130 
131 	if(mode != tty_mode && mode != -1) {
132 		if(!handlerIsSet) {
133 			/* Determine existing TTY settings */
134 			gtty (STDIN, &in_orig);
135 			need_tty_reset = 1;
136 
137 			/* Restore original TTY settings on exit */
138 			atexit(cleanup_tty);
139 			handlerIsSet = 1;
140 		}
141 
142 
143 		setup_signal();
144 		signal (SIGALRM, tty_time_out);
145 
146 		/* Change STDIN settings to raw */
147 
148 		gtty (STDIN, &in_raw);
149 		if(mode) {
150 #ifdef USE_SGTTY
151 			in_raw.sg_flags |= CBREAK;
152 #else
153 			in_raw.c_lflag &= ~0u ^ ICANON;
154 			in_raw.c_cc[VMIN]=1;
155 			in_raw.c_cc[VTIME]=0;
156 #endif
157 			stty (STDIN, &in_raw);
158 		} else {
159 #ifdef USE_SGTTY
160 			in_raw.sg_flags &= ~CBREAK;
161 #else
162 			in_raw.c_lflag |= ICANON;
163 #endif
164 			stty (STDIN, &in_raw);
165 		}
166 		tty_mode = mode;
167 		discard_input(STDIN);
168 	}
169 }
170 #endif
171 
opentty(int mode UNUSEDP)172 FILE *opentty(int mode UNUSEDP)
173 {
174 	if(notty)
175 		return NULL;
176 	if (tty == NULL) {
177 		ttyfd = open("/dev/tty", O_RDONLY);
178 		if(ttyfd >= 0) {
179 			tty = fdopen(ttyfd, "r");
180 		}
181 	}
182 	if  (tty == NULL){
183 		if ( !isatty(0) ){
184 			notty = 1;
185 			return NULL;
186 		}
187 		ttyfd = 0;
188 		tty = stdin;
189 	}
190 #ifdef USE_RAWTERM
191 	if(mtools_raw_tty)
192 		set_raw_tty(mode);
193 #endif
194 	return tty;
195 }
196 
ask_confirmation(const char * format,...)197 int ask_confirmation(const char *format, ...)
198 {
199 	char ans[10];
200 	va_list ap;
201 
202 	if(!opentty(-1))
203 		return 0;
204 
205 	while (1) {
206 		va_start(ap, format);
207 		vfprintf(stderr, format, ap);
208 		va_end(ap);
209 		fflush(stderr);
210 		fflush(opentty(-1));
211 		if (mtools_raw_tty) {
212 			int c = fgetc(opentty(1));
213 			if(c < 0)
214 				/* Treat end-of-file or error as no */
215 				ans[0] = 'n';
216 			else
217 				ans[0] = (char) c;
218 			fputs("\n", stderr);
219 		} else {
220 			if(fgets(ans,9, opentty(0)) == NULL)
221 				/* Treat end-of-file as no */
222 				ans[0] = 'n';
223 		}
224 		if (ans[0] == 'y' || ans[0] == 'Y')
225 			return 0;
226 		if (ans[0] == 'n' || ans[0] == 'N')
227 			return -1;
228 	}
229 }
230