1 /* -*-C-*-
2
3 Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
4 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Massachusetts
6 Institute of Technology
7
8 This file is part of MIT/GNU Scheme.
9
10 MIT/GNU Scheme is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or (at
13 your option) any later version.
14
15 MIT/GNU Scheme is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with MIT/GNU Scheme; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
23 USA.
24
25 */
26
27 #include "scheme.h"
28 #include "ux.h"
29 #include "uxutil.h"
30 #include <ctype.h>
31
32 extern void terminal_state_raw (Ttty_state *, int);
33
34 static const char *
char_description_brief(unsigned char c)35 char_description_brief (unsigned char c)
36 {
37 static char buffer [5];
38 switch (c)
39 {
40 case ' ': return ("SPC");
41 case '\t': return ("TAB");
42 case '\r': return ("RET");
43 case '\n': return ("LFD");
44 case '\033': return ("ESC");
45 case '\177': return ("DEL");
46 default:
47 if (c < ' ')
48 {
49 (buffer[0]) = '^';
50 (buffer[1]) = (c + '@');
51 (buffer[2]) = '\0';
52 }
53 else if (c < '\177')
54 {
55 (buffer[0]) = c;
56 (buffer[1]) = '\0';
57 }
58 else
59 {
60 (buffer[0]) = '\\';
61 (buffer[1]) = (c >> 6);
62 (buffer[2]) = ((c >> 3) & 7);
63 (buffer[3]) = (c & 7);
64 (buffer[4]) = '\0';
65 }
66 return (buffer);
67 }
68 }
69
70 const char *
char_description(unsigned char c,int long_p)71 char_description (unsigned char c, int long_p)
72 {
73 static char buffer [64];
74 const char * description = (char_description_brief (c));
75 if (long_p)
76 {
77 int meta = (c >= 0200);
78 int cc = (c & 0177);
79 int control = (cc < 0040);
80 if (meta || control)
81 {
82 sprintf (buffer, "`%s' (%s%s%c)",
83 description,
84 (meta ? "meta-" : ""),
85 (control ? "control-" : ""),
86 (control ? (cc + 0100) : cc));
87 return (buffer);
88 }
89 }
90 sprintf (buffer, "`%s'", description);
91 return (buffer);
92 }
93
94 static Ttty_state original_tty_state;
95
96 void
UX_initialize_userio(void)97 UX_initialize_userio (void)
98 {
99 UX_terminal_get_state (STDIN_FILENO, (&original_tty_state));
100 }
101
102 static void
restore_input_state(void * ap)103 restore_input_state (void * ap)
104 {
105 UX_terminal_set_state (STDIN_FILENO, ap);
106 }
107
108 static Ttty_state *
save_input_state(void)109 save_input_state (void)
110 {
111 Ttty_state * s = (dstack_alloc (sizeof (Ttty_state)));
112 UX_terminal_get_state (STDIN_FILENO, s);
113 transaction_record_action (tat_always, restore_input_state, s);
114 return (s);
115 }
116
117 void
userio_buffered_input(void)118 userio_buffered_input (void)
119 {
120 save_input_state ();
121 UX_terminal_set_state (STDIN_FILENO, (&original_tty_state));
122 }
123
124 char
userio_read_char(void)125 userio_read_char (void)
126 {
127 char c;
128 while (1)
129 {
130 int nread;
131
132 errno = 0;
133 nread = (UX_read (STDIN_FILENO, (&c), 1));
134 if (nread == 1)
135 break;
136 if (errno != EINTR)
137 {
138 c = '\0';
139 break;
140 }
141 }
142 return (c);
143 }
144
145 char
userio_read_char_raw(void)146 userio_read_char_raw (void)
147 {
148 transaction_begin ();
149 {
150 /* Must split declaration and assignment because some compilers
151 do not permit aggregate initializers. */
152 Ttty_state state;
153 state = (* (save_input_state ()));
154 terminal_state_raw ((&state), STDIN_FILENO);
155 UX_terminal_set_state (STDIN_FILENO, (&state));
156 }
157 {
158 char c = (userio_read_char ());
159 transaction_commit ();
160 return (c);
161 }
162 }
163
164 char
userio_choose_option(const char * herald,const char * prompt,const char ** choices)165 userio_choose_option (const char * herald,
166 const char * prompt,
167 const char ** choices)
168 {
169 while (1)
170 {
171 fputs (herald, stdout);
172 putc ('\n', stdout);
173 {
174 const char ** scan = choices;
175 while (1)
176 {
177 const char * choice = (*scan++);
178 if (choice == 0)
179 break;
180 fprintf (stdout, " %s\n", choice);
181 }
182 }
183 fputs (prompt, stdout);
184 fflush (stdout);
185 {
186 unsigned char command = ((unsigned char) (userio_read_char_raw ()));
187 if ((command == '\0') && (errno != 0))
188 return (command);
189 putc ('\n', stdout);
190 fflush (stdout);
191 if (islower (command))
192 command = (toupper (command));
193 {
194 const char ** scan = choices;
195 while (1)
196 {
197 const char * choice = (*scan++);
198 if (choice == 0)
199 break;
200 {
201 unsigned char option = (*choice);
202 if (islower (option))
203 option = (toupper (option));
204 if (command == option)
205 return (option);
206 }
207 }
208 }
209 }
210 }
211 }
212
213 int
userio_confirm(const char * prompt)214 userio_confirm (const char * prompt)
215 {
216 while (1)
217 {
218 fputs (prompt, stdout);
219 fflush (stdout);
220 switch (userio_read_char_raw ())
221 {
222 case 'y':
223 case 'Y':
224 return (1);
225 case 'n':
226 case 'N':
227 return (0);
228 case '\0':
229 if (errno != 0)
230 {
231 /* IO problems, assume everything scrod. */
232 fprintf (stderr, "Problems reading keyboard input -- exiting.\n");
233 termination_eof ();
234 }
235 }
236 }
237 }
238