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 "option.h"
29 #include "ux.h"
30 #include "ostty.h"
31 #include "osenv.h"
32 #include "uxio.h"
33 #include "uxterm.h"
34
35 extern Tchannel OS_open_fd (int fd);
36 #ifdef USE_TERMCAP
37 extern int tgetent (void *, const char *);
38 extern int tgetnum (const char *);
39 extern const char * tgetstr (const char *, char **);
40 extern void tputs (const char *, int, void (*) (char));
41 #endif
42
43 /* Standard Input and Output */
44
45 static Tchannel input_channel;
46 static Tchannel output_channel;
47
48 static int tty_x_size;
49 static int tty_y_size;
50 static const char * tty_command_beep;
51 static const char * tty_command_clear;
52
53 static bool tty_size_synchronized_p;
54 static void UX_synchronize_tty_size (void);
55
56 Tchannel
OS_tty_input_channel(void)57 OS_tty_input_channel (void)
58 {
59 return (input_channel);
60 }
61
62 Tchannel
OS_tty_output_channel(void)63 OS_tty_output_channel (void)
64 {
65 return (output_channel);
66 }
67
68 unsigned int
OS_tty_x_size(void)69 OS_tty_x_size (void)
70 {
71 UX_synchronize_tty_size ();
72 return (tty_x_size);
73 }
74
75 unsigned int
OS_tty_y_size(void)76 OS_tty_y_size (void)
77 {
78 UX_synchronize_tty_size ();
79 return (tty_y_size);
80 }
81
82 const char *
OS_tty_command_beep(void)83 OS_tty_command_beep (void)
84 {
85 return (tty_command_beep);
86 }
87
88 const char *
OS_tty_command_clear(void)89 OS_tty_command_clear (void)
90 {
91 return (tty_command_clear);
92 }
93
94 #ifndef TERMCAP_BUFFER_SIZE
95 #define TERMCAP_BUFFER_SIZE 2048
96 #endif
97
98 #ifndef DEFAULT_TTY_X_SIZE
99 #define DEFAULT_TTY_X_SIZE 80
100 #endif
101
102 #ifndef DEFAULT_TTY_Y_SIZE
103 #define DEFAULT_TTY_Y_SIZE 24
104 #endif
105
106 /* Define the 4.3 names in terms of the Sun names
107 if the latter exist and the former do not. */
108 #ifdef TIOCGSIZE
109 #ifndef TIOCGWINSZ
110 #define TIOCGWINSZ TIOCGSIZE
111 #define winsize ttysize
112 #define ws_row ts_lines
113 #define ws_col ts_cols
114 #endif /* not TIOCGWINSZ */
115 #endif /* TIOCGSIZE */
116
117 #ifdef USE_TERMCAP
118 static char tputs_output [TERMCAP_BUFFER_SIZE];
119 static char * tputs_output_scan;
120
121 static void
tputs_write_char(char c)122 tputs_write_char (char c)
123 {
124 (*tputs_output_scan++) = c;
125 }
126
127 static void
UX_tty_with_termcap(void (* procedure)(void))128 UX_tty_with_termcap (void (*procedure) (void))
129 {
130 tputs_output_scan = tputs_output;
131 {
132 char termcap_buffer [TERMCAP_BUFFER_SIZE];
133 const char *term;
134 if ((isatty (STDOUT_FILENO))
135 && (!option_emacs_subprocess)
136 && ((term = (getenv ("TERM"))) != 0)
137 && ((tgetent (termcap_buffer, term)) > 0))
138 (*procedure) ();
139 }
140 }
141
142 static void
UX_synchronize_tty_size_with_termcap(void)143 UX_synchronize_tty_size_with_termcap (void)
144 {
145 tty_x_size = (tgetnum ("co"));
146 tty_y_size = (tgetnum ("li"));
147 }
148 #endif /* USE_TERMCAP */
149
150 static void
UX_synchronize_tty_size(void)151 UX_synchronize_tty_size (void)
152 {
153 if (tty_size_synchronized_p)
154 return;
155
156 tty_x_size = (-1);
157 tty_y_size = (-1);
158
159 /* Figure out the size of the terminal. First ask the operating
160 system, if it has an appropriate system call. Then try the
161 environment variables COLUMNS and LINES. Then try termcap.
162 Finally, use the default. */
163 #ifdef TIOCGWINSZ
164 {
165 struct winsize size;
166 if ((UX_ioctl (STDOUT_FILENO, TIOCGWINSZ, (&size))) >= 0)
167 {
168 tty_x_size = (size . ws_col);
169 tty_y_size = (size . ws_row);
170 }
171 }
172 #endif /* TIOCGWINSZ */
173
174 if ((tty_x_size <= 0) || (tty_y_size <= 0))
175 {
176 const char * columns = (UX_getenv ("COLUMNS"));
177 const char * lines = (UX_getenv ("LINES"));
178 if ((columns != 0) && (lines != 0))
179 {
180 int x = (atoi (columns));
181 int y = (atoi (lines));
182 if ((x > 0) && (y > 0))
183 {
184 tty_x_size = x;
185 tty_y_size = y;
186 }
187 }
188 }
189
190 #ifdef USE_TERMCAP
191 if ((tty_x_size <= 0) || (tty_y_size <= 0))
192 UX_tty_with_termcap (&UX_synchronize_tty_size_with_termcap);
193 #endif
194
195 if ((tty_x_size <= 0) || (tty_y_size <= 0))
196 {
197 tty_x_size = DEFAULT_TTY_X_SIZE;
198 tty_y_size = DEFAULT_TTY_Y_SIZE;
199 }
200
201 tty_size_synchronized_p = true;
202 }
203
204 #ifdef USE_TERMCAP
205 static void
UX_initialize_tty_with_termcap(void)206 UX_initialize_tty_with_termcap (void)
207 {
208 static char tgetstr_buffer [TERMCAP_BUFFER_SIZE];
209 char *tbp = tgetstr_buffer;
210 tty_command_clear = (tgetstr ("cl", (&tbp)));
211 }
212 #endif
213
214 void
UX_initialize_tty(void)215 UX_initialize_tty (void)
216 {
217 input_channel = (OS_open_fd (STDIN_FILENO));
218 (CHANNEL_INTERNAL (input_channel)) = 1;
219 output_channel = (OS_open_fd (STDOUT_FILENO));
220 (CHANNEL_INTERNAL (output_channel)) = 1;
221 tty_size_synchronized_p = false;
222 UX_synchronize_tty_size ();
223 tty_command_beep = ALERT_STRING;
224 #ifndef USE_TERMCAP
225 tty_command_clear = "\f";
226 #else
227 tty_command_clear = 0;
228 UX_tty_with_termcap (&UX_initialize_tty_with_termcap);
229 if (tty_command_clear == 0)
230 tty_command_clear = "\f";
231 else
232 {
233 char * command = tputs_output_scan;
234 tputs (tty_command_clear, tty_y_size, tputs_write_char);
235 (*tputs_output_scan++) = '\0';
236 tty_command_clear = command;
237 }
238 #endif
239 }
240
241 void
UX_reinitialize_tty(void)242 UX_reinitialize_tty (void)
243 {
244 tty_size_synchronized_p = false;
245 }
246