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