tty.c revision 1.22 1 /* $NetBSD: tty.c,v 1.22 2000/06/15 21:20:16 jdc Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)tty.c 8.6 (Berkeley) 1/10/95";
40 #else
41 __RCSID("$NetBSD: tty.c,v 1.22 2000/06/15 21:20:16 jdc Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include <sys/types.h>
46
47 #include <stdlib.h>
48 #include <termios.h>
49 #include <unistd.h>
50 #include <sys/fcntl.h>
51 #include <sys/ioctl.h>
52
53 #include "curses.h"
54 #include "curses_private.h"
55
56 /*
57 * In general, curses should leave tty hardware settings alone (speed, parity,
58 * word size). This is most easily done in BSD by using TCSASOFT on all
59 * tcsetattr calls. On other systems, it would be better to get and restore
60 * those attributes at each change, or at least when stopped and restarted.
61 * See also the comments in getterm().
62 */
63 #ifdef TCSASOFT
64 int __tcaction = 1; /* Ignore hardware settings. */
65 #else
66 int __tcaction = 0;
67 #endif
68
69 struct termios __orig_termios, __baset;
70 int __endwin;
71 static struct termios cbreakt, rawt, *curt;
72 static int useraw;
73 static int ovmin = 1;
74 static int ovtime = 0;
75
76 #ifndef OXTABS
77 #ifdef XTABS /* SMI uses XTABS. */
78 #define OXTABS XTABS
79 #else
80 #define OXTABS 0
81 #endif
82 #endif
83
84 /*
85 * gettmode --
86 * Do terminal type initialization.
87 */
88 int
89 gettmode(void)
90 {
91 useraw = 0;
92
93 if (tcgetattr(STDIN_FILENO, &__orig_termios))
94 return (ERR);
95
96 __baset = __orig_termios;
97 __baset.c_oflag &= ~OXTABS;
98
99 GT = 0; /* historical. was used before we wired OXTABS
100 * off */
101 NONL = (__baset.c_oflag & ONLCR) == 0;
102
103 /*
104 * XXX
105 * System V and SMI systems overload VMIN and VTIME, such that
106 * VMIN is the same as the VEOF element, and VTIME is the same
107 * as the VEOL element. This means that, if VEOF was ^D, the
108 * default VMIN is 4. Majorly stupid.
109 */
110 cbreakt = __baset;
111 cbreakt.c_lflag &= ~(ECHO | ECHONL | ICANON);
112 cbreakt.c_cc[VMIN] = 1;
113 cbreakt.c_cc[VTIME] = 0;
114
115 rawt = cbreakt;
116 rawt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INLCR | IGNCR | ICRNL | IXON);
117 rawt.c_oflag &= ~OPOST;
118 rawt.c_lflag &= ~(ISIG | IEXTEN);
119
120 /*
121 * In general, curses should leave hardware-related settings alone.
122 * This includes parity and word size. Older versions set the tty
123 * to 8 bits, no parity in raw(), but this is considered to be an
124 * artifact of the old tty interface. If it's desired to change
125 * parity and word size, the TCSASOFT bit has to be removed from the
126 * calls that switch to/from "raw" mode.
127 */
128 if (!__tcaction) {
129 rawt.c_iflag &= ~ISTRIP;
130 rawt.c_cflag &= ~(CSIZE | PARENB);
131 rawt.c_cflag |= CS8;
132 }
133
134 curt = &__baset;
135 return (tcsetattr(STDIN_FILENO, __tcaction ?
136 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
137 }
138
139 int
140 raw(void)
141 {
142 /* Check if we need to restart ... */
143 if (__endwin)
144 __endwin = 0;
145
146 useraw = __pfast = __rawmode = 1;
147 curt = &rawt;
148 return (tcsetattr(STDIN_FILENO, __tcaction ?
149 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
150 }
151
152 int
153 noraw(void)
154 {
155 /* Check if we need to restart ... */
156 if (__endwin)
157 __endwin = 0;
158
159 useraw = __pfast = __rawmode = 0;
160 curt = &__baset;
161 return (tcsetattr(STDIN_FILENO, __tcaction ?
162 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
163 }
164
165 int
166 cbreak(void)
167 {
168 /* Check if we need to restart ... */
169 if (__endwin)
170 __endwin = 0;
171
172 __rawmode = 1;
173 curt = useraw ? &rawt : &cbreakt;
174 return (tcsetattr(STDIN_FILENO, __tcaction ?
175 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
176 }
177
178 int
179 nocbreak(void)
180 {
181 /* Check if we need to restart ... */
182 if (__endwin)
183 __endwin = 0;
184
185 __rawmode = 0;
186 curt = useraw ? &rawt : &__baset;
187 return (tcsetattr(STDIN_FILENO, __tcaction ?
188 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
189 }
190
191 int
192 __delay(void)
193 {
194 /* Check if we need to restart ... */
195 if (__endwin)
196 __endwin = 0;
197
198 rawt.c_cc[VMIN] = 1;
199 rawt.c_cc[VTIME] = 0;
200 cbreakt.c_cc[VMIN] = 1;
201 cbreakt.c_cc[VTIME] = 0;
202 __baset.c_cc[VMIN] = 1;
203 __baset.c_cc[VTIME] = 0;
204
205 return (tcsetattr(STDIN_FILENO, __tcaction ?
206 TCSASOFT : TCSANOW, curt) ? ERR : OK);
207 }
208
209 int
210 __nodelay(void)
211 {
212 /* Check if we need to restart ... */
213 if (__endwin)
214 __endwin = 0;
215
216 rawt.c_cc[VMIN] = 0;
217 rawt.c_cc[VTIME] = 0;
218 cbreakt.c_cc[VMIN] = 0;
219 cbreakt.c_cc[VTIME] = 0;
220 __baset.c_cc[VMIN] = 0;
221 __baset.c_cc[VTIME] = 0;
222
223 return (tcsetattr(STDIN_FILENO, __tcaction ?
224 TCSASOFT : TCSANOW, curt) ? ERR : OK);
225 }
226
227 void
228 __save_termios(void)
229 {
230 /* Check if we need to restart ... */
231 if (__endwin)
232 __endwin = 0;
233
234 ovmin = cbreakt.c_cc[VMIN];
235 ovtime = cbreakt.c_cc[VTIME];
236 }
237
238 void
239 __restore_termios(void)
240 {
241 /* Check if we need to restart ... */
242 if (__endwin)
243 __endwin = 0;
244
245 rawt.c_cc[VMIN] = ovmin;
246 rawt.c_cc[VTIME] = ovtime;
247 cbreakt.c_cc[VMIN] = ovmin;
248 cbreakt.c_cc[VTIME] = ovtime;
249 __baset.c_cc[VMIN] = ovmin;
250 __baset.c_cc[VTIME] = ovtime;
251 }
252
253 int
254 __timeout(int delay)
255 {
256 /* Check if we need to restart ... */
257 if (__endwin)
258 __endwin = 0;
259
260 ovmin = cbreakt.c_cc[VMIN];
261 ovtime = cbreakt.c_cc[VTIME];
262 rawt.c_cc[VMIN] = 0;
263 rawt.c_cc[VTIME] = delay;
264 cbreakt.c_cc[VMIN] = 0;
265 cbreakt.c_cc[VTIME] = delay;
266 __baset.c_cc[VMIN] = 0;
267 __baset.c_cc[VTIME] = delay;
268
269 return (tcsetattr(STDIN_FILENO, __tcaction ?
270 TCSASOFT | TCSANOW : TCSANOW, curt) ? ERR : OK);
271 }
272
273 int
274 __notimeout(void)
275 {
276 /* Check if we need to restart ... */
277 if (__endwin)
278 __endwin = 0;
279
280 rawt.c_cc[VMIN] = 1;
281 rawt.c_cc[VTIME] = 0;
282 cbreakt.c_cc[VMIN] = 1;
283 cbreakt.c_cc[VTIME] = 0;
284 __baset.c_cc[VMIN] = 1;
285 __baset.c_cc[VTIME] = 0;
286
287 return (tcsetattr(STDIN_FILENO, __tcaction ?
288 TCSASOFT | TCSANOW : TCSANOW, curt) ? ERR : OK);
289 }
290
291 int
292 echo(void)
293 {
294 /* Check if we need to restart ... */
295 if (__endwin)
296 __endwin = 0;
297
298 __echoit = 1;
299 return (OK);
300 }
301
302 int
303 noecho(void)
304 {
305 /* Check if we need to restart ... */
306 if (__endwin)
307 __endwin = 0;
308
309 __echoit = 0;
310 return (OK);
311 }
312
313 int
314 nl(void)
315 {
316 /* Check if we need to restart ... */
317 if (__endwin)
318 __endwin = 0;
319
320 rawt.c_iflag |= ICRNL;
321 rawt.c_oflag |= ONLCR;
322 cbreakt.c_iflag |= ICRNL;
323 cbreakt.c_oflag |= ONLCR;
324 __baset.c_iflag |= ICRNL;
325 __baset.c_oflag |= ONLCR;
326
327 __pfast = __rawmode;
328 return (tcsetattr(STDIN_FILENO, __tcaction ?
329 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
330 }
331
332 int
333 nonl(void)
334 {
335 /* Check if we need to restart ... */
336 if (__endwin)
337 __endwin = 0;
338
339 rawt.c_iflag &= ~ICRNL;
340 rawt.c_oflag &= ~ONLCR;
341 cbreakt.c_iflag &= ~ICRNL;
342 cbreakt.c_oflag &= ~ONLCR;
343 __baset.c_iflag &= ~ICRNL;
344 __baset.c_oflag &= ~ONLCR;
345
346 __pfast = 1;
347 return (tcsetattr(STDIN_FILENO, __tcaction ?
348 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
349 }
350
351 int
352 intrflush(WINDOW *win, bool bf) /*ARGSUSED*/
353 {
354 /* Check if we need to restart ... */
355 if (__endwin)
356 __endwin = 0;
357
358 if (bf) {
359 rawt.c_lflag &= ~NOFLSH;
360 cbreakt.c_lflag &= ~NOFLSH;
361 __baset.c_lflag &= ~NOFLSH;
362 } else {
363 rawt.c_lflag |= NOFLSH;
364 cbreakt.c_lflag |= NOFLSH;
365 __baset.c_lflag |= NOFLSH;
366 }
367
368 __pfast = 1;
369 return (tcsetattr(STDIN_FILENO, __tcaction ?
370 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
371 }
372
373 void
374 __startwin(void)
375 {
376 static char *stdbuf;
377 static size_t len;
378
379 (void) fflush(stdout);
380
381 /*
382 * Some C libraries default to a 1K buffer when talking to a tty.
383 * With a larger screen, especially across a network, we'd like
384 * to get it to all flush in a single write. Make it twice as big
385 * as just the characters (so that we have room for cursor motions
386 * and attribute information) but no more than 8K.
387 */
388 if (stdbuf == NULL) {
389 if ((len = LINES * COLS * 2) > 8192)
390 len = 8192;
391 if ((stdbuf = malloc(len)) == NULL)
392 len = 0;
393 }
394 (void) setvbuf(stdout, stdbuf, _IOFBF, len);
395
396 tputs(TI, 0, __cputchar);
397 tputs(VS, 0, __cputchar);
398 if (curscr->flags & __KEYPAD)
399 tputs(KS, 0, __cputchar);
400 __endwin = 0;
401 }
402
403 int
404 endwin(void)
405 {
406 return __stopwin();
407 }
408
409 bool
410 isendwin(void)
411 {
412 return (__endwin ? TRUE : FALSE);
413 }
414
415 int
416 flushinp(void)
417 {
418 (void) fpurge(stdin);
419 return (OK);
420 }
421
422 /*
423 * The following routines, savetty and resetty are completely useless and
424 * are left in only as stubs. If people actually use them they will almost
425 * certainly screw up the state of the world.
426 */
427 static struct termios savedtty;
428 int
429 savetty(void)
430 {
431 return (tcgetattr(STDIN_FILENO, &savedtty) ? ERR : OK);
432 }
433
434 int
435 resetty(void)
436 {
437 return (tcsetattr(STDIN_FILENO, __tcaction ?
438 TCSASOFT | TCSADRAIN : TCSADRAIN, &savedtty) ? ERR : OK);
439 }
440
441 /*
442 * erasechar --
443 * Return the character of the erase key.
444 *
445 */
446 char
447 erasechar(void)
448 {
449 return __baset.c_cc[VERASE];
450 }
451
452 /*
453 * killchar --
454 * Return the character of the kill key.
455 */
456 char
457 killchar(void)
458 {
459 return __baset.c_cc[VKILL];
460 }
461