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