tty.c revision 1.25 1 /* $NetBSD: tty.c,v 1.25 2001/12/02 09:14:23 blymn 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.25 2001/12/02 09:14:23 blymn 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 if (_cursesi_gettmode(_cursesi_screen) == ERR)
92 return ERR;
93
94 __GT = _cursesi_screen->GT;
95 __NONL = _cursesi_screen->NONL;
96 return OK;
97 }
98
99 /*
100 * _cursesi_gettmode --
101 * Do the terminal type initialisation for the tty attached to the
102 * given screen.
103 */
104 int
105 _cursesi_gettmode(SCREEN *screen)
106 {
107 screen->useraw = 0;
108
109 if (tcgetattr(fileno(screen->infd), &screen->orig_termios))
110 return (ERR);
111
112 screen->baset = screen->orig_termios;
113 screen->baset.c_oflag &= ~OXTABS;
114
115 screen->GT = 0; /* historical. was used before we wired OXTABS off */
116 screen->NONL = (screen->baset.c_oflag & ONLCR) == 0;
117
118 /*
119 * XXX
120 * System V and SMI systems overload VMIN and VTIME, such that
121 * VMIN is the same as the VEOF element, and VTIME is the same
122 * as the VEOL element. This means that, if VEOF was ^D, the
123 * default VMIN is 4. Majorly stupid.
124 */
125 screen->cbreakt = screen->baset;
126 screen->cbreakt.c_lflag &= ~(ECHO | ECHONL | ICANON);
127 screen->cbreakt.c_cc[VMIN] = 1;
128 screen->cbreakt.c_cc[VTIME] = 0;
129
130 screen->rawt = screen->cbreakt;
131 screen->rawt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INLCR | IGNCR |
132 ICRNL | IXON);
133 screen->rawt.c_oflag &= ~OPOST;
134 screen->rawt.c_lflag &= ~(ISIG | IEXTEN);
135
136 /*
137 * In general, curses should leave hardware-related settings alone.
138 * This includes parity and word size. Older versions set the tty
139 * to 8 bits, no parity in raw(), but this is considered to be an
140 * artifact of the old tty interface. If it's desired to change
141 * parity and word size, the TCSASOFT bit has to be removed from the
142 * calls that switch to/from "raw" mode.
143 */
144 if (!__tcaction) {
145 screen->rawt.c_iflag &= ~ISTRIP;
146 screen->rawt.c_cflag &= ~(CSIZE | PARENB);
147 screen->rawt.c_cflag |= CS8;
148 }
149
150 screen->curt = &screen->baset;
151 return (tcsetattr(fileno(screen->infd), __tcaction ?
152 TCSASOFT | TCSADRAIN : TCSADRAIN, screen->curt) ? ERR : OK);
153 }
154
155 int
156 raw(void)
157 {
158 /* Check if we need to restart ... */
159 if (_cursesi_screen->endwin)
160 __restartwin();
161
162 _cursesi_screen->useraw = __pfast = __rawmode = 1;
163 _cursesi_screen->curt = &_cursesi_screen->rawt;
164 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
165 TCSASOFT | TCSADRAIN : TCSADRAIN,
166 _cursesi_screen->curt) ? ERR : OK);
167 }
168
169 int
170 noraw(void)
171 {
172 /* Check if we need to restart ... */
173 if (_cursesi_screen->endwin)
174 __restartwin();
175
176 _cursesi_screen->useraw = __pfast = __rawmode = 0;
177 _cursesi_screen->curt = &_cursesi_screen->baset;
178 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
179 TCSASOFT | TCSADRAIN : TCSADRAIN,
180 _cursesi_screen->curt) ? ERR : OK);
181 }
182
183 int
184 cbreak(void)
185 {
186 /* Check if we need to restart ... */
187 if (_cursesi_screen->endwin)
188 __restartwin();
189
190 __rawmode = 1;
191 _cursesi_screen->curt = _cursesi_screen->useraw ?
192 &_cursesi_screen->rawt : &_cursesi_screen->cbreakt;
193 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
194 TCSASOFT | TCSADRAIN : TCSADRAIN,
195 _cursesi_screen->curt) ? ERR : OK);
196 }
197
198 int
199 nocbreak(void)
200 {
201 /* Check if we need to restart ... */
202 if (_cursesi_screen->endwin)
203 __restartwin();
204
205 __rawmode = 0;
206 _cursesi_screen->curt = _cursesi_screen->useraw ?
207 &_cursesi_screen->rawt : &_cursesi_screen->baset;
208 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
209 TCSASOFT | TCSADRAIN : TCSADRAIN,
210 _cursesi_screen->curt) ? ERR : OK);
211 }
212
213 int
214 __delay(void)
215 {
216 /* Check if we need to restart ... */
217 if (_cursesi_screen->endwin)
218 __restartwin();
219
220 _cursesi_screen->rawt.c_cc[VMIN] = 1;
221 _cursesi_screen->rawt.c_cc[VTIME] = 0;
222 _cursesi_screen->cbreakt.c_cc[VMIN] = 1;
223 _cursesi_screen->cbreakt.c_cc[VTIME] = 0;
224 _cursesi_screen->baset.c_cc[VMIN] = 1;
225 _cursesi_screen->baset.c_cc[VTIME] = 0;
226
227 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
228 TCSASOFT : TCSANOW, _cursesi_screen->curt) ? ERR : OK);
229 }
230
231 int
232 __nodelay(void)
233 {
234 /* Check if we need to restart ... */
235 if (_cursesi_screen->endwin)
236 __restartwin();
237
238 _cursesi_screen->rawt.c_cc[VMIN] = 0;
239 _cursesi_screen->rawt.c_cc[VTIME] = 0;
240 _cursesi_screen->cbreakt.c_cc[VMIN] = 0;
241 _cursesi_screen->cbreakt.c_cc[VTIME] = 0;
242 _cursesi_screen->baset.c_cc[VMIN] = 0;
243 _cursesi_screen->baset.c_cc[VTIME] = 0;
244
245 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
246 TCSASOFT : TCSANOW, _cursesi_screen->curt) ? ERR : OK);
247 }
248
249 void
250 __save_termios(void)
251 {
252 /* Check if we need to restart ... */
253 if (_cursesi_screen->endwin)
254 __restartwin();
255
256 _cursesi_screen->ovmin = _cursesi_screen->cbreakt.c_cc[VMIN];
257 _cursesi_screen->ovtime = _cursesi_screen->cbreakt.c_cc[VTIME];
258 }
259
260 void
261 __restore_termios(void)
262 {
263 /* Check if we need to restart ... */
264 if (_cursesi_screen->endwin)
265 __restartwin();
266
267 _cursesi_screen->rawt.c_cc[VMIN] = _cursesi_screen->ovmin;
268 _cursesi_screen->rawt.c_cc[VTIME] = _cursesi_screen->ovtime;
269 _cursesi_screen->cbreakt.c_cc[VMIN] = _cursesi_screen->ovmin;
270 _cursesi_screen->cbreakt.c_cc[VTIME] = _cursesi_screen->ovtime;
271 _cursesi_screen->baset.c_cc[VMIN] = _cursesi_screen->ovmin;
272 _cursesi_screen->baset.c_cc[VTIME] = _cursesi_screen->ovtime;
273 }
274
275 int
276 __timeout(int delay)
277 {
278 /* Check if we need to restart ... */
279 if (_cursesi_screen->endwin)
280 __restartwin();
281
282 _cursesi_screen->ovmin = _cursesi_screen->cbreakt.c_cc[VMIN];
283 _cursesi_screen->ovtime = _cursesi_screen->cbreakt.c_cc[VTIME];
284 _cursesi_screen->rawt.c_cc[VMIN] = 0;
285 _cursesi_screen->rawt.c_cc[VTIME] = delay;
286 _cursesi_screen->cbreakt.c_cc[VMIN] = 0;
287 _cursesi_screen->cbreakt.c_cc[VTIME] = delay;
288 _cursesi_screen->baset.c_cc[VMIN] = 0;
289 _cursesi_screen->baset.c_cc[VTIME] = delay;
290
291 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
292 TCSASOFT | TCSANOW : TCSANOW,
293 _cursesi_screen->curt) ? ERR : OK);
294 }
295
296 int
297 __notimeout(void)
298 {
299 /* Check if we need to restart ... */
300 if (_cursesi_screen->endwin)
301 __restartwin();
302
303 _cursesi_screen->rawt.c_cc[VMIN] = 1;
304 _cursesi_screen->rawt.c_cc[VTIME] = 0;
305 _cursesi_screen->cbreakt.c_cc[VMIN] = 1;
306 _cursesi_screen->cbreakt.c_cc[VTIME] = 0;
307 _cursesi_screen->baset.c_cc[VMIN] = 1;
308 _cursesi_screen->baset.c_cc[VTIME] = 0;
309
310 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
311 TCSASOFT | TCSANOW : TCSANOW,
312 _cursesi_screen->curt) ? ERR : OK);
313 }
314
315 int
316 echo(void)
317 {
318 /* Check if we need to restart ... */
319 if (_cursesi_screen->endwin)
320 __restartwin();
321
322 __echoit = 1;
323 return (OK);
324 }
325
326 int
327 noecho(void)
328 {
329 /* Check if we need to restart ... */
330 if (_cursesi_screen->endwin)
331 __restartwin();
332
333 __echoit = 0;
334 return (OK);
335 }
336
337 int
338 nl(void)
339 {
340 /* Check if we need to restart ... */
341 if (_cursesi_screen->endwin)
342 __restartwin();
343
344 _cursesi_screen->rawt.c_iflag |= ICRNL;
345 _cursesi_screen->rawt.c_oflag |= ONLCR;
346 _cursesi_screen->cbreakt.c_iflag |= ICRNL;
347 _cursesi_screen->cbreakt.c_oflag |= ONLCR;
348 _cursesi_screen->baset.c_iflag |= ICRNL;
349 _cursesi_screen->baset.c_oflag |= ONLCR;
350
351 _cursesi_screen->pfast = _cursesi_screen->rawmode;
352 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
353 TCSASOFT | TCSADRAIN : TCSADRAIN,
354 _cursesi_screen->curt) ? ERR : OK);
355 }
356
357 int
358 nonl(void)
359 {
360 /* Check if we need to restart ... */
361 if (_cursesi_screen->endwin)
362 __restartwin();
363
364 _cursesi_screen->rawt.c_iflag &= ~ICRNL;
365 _cursesi_screen->rawt.c_oflag &= ~ONLCR;
366 _cursesi_screen->cbreakt.c_iflag &= ~ICRNL;
367 _cursesi_screen->cbreakt.c_oflag &= ~ONLCR;
368 _cursesi_screen->baset.c_iflag &= ~ICRNL;
369 _cursesi_screen->baset.c_oflag &= ~ONLCR;
370
371 __pfast = 1;
372 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
373 TCSASOFT | TCSADRAIN : TCSADRAIN,
374 _cursesi_screen->curt) ? ERR : OK);
375 }
376
377 int
378 intrflush(WINDOW *win, bool bf) /*ARGSUSED*/
379 {
380 /* Check if we need to restart ... */
381 if (_cursesi_screen->endwin)
382 __restartwin();
383
384 if (bf) {
385 _cursesi_screen->rawt.c_lflag &= ~NOFLSH;
386 _cursesi_screen->cbreakt.c_lflag &= ~NOFLSH;
387 _cursesi_screen->baset.c_lflag &= ~NOFLSH;
388 } else {
389 _cursesi_screen->rawt.c_lflag |= NOFLSH;
390 _cursesi_screen->cbreakt.c_lflag |= NOFLSH;
391 _cursesi_screen->baset.c_lflag |= NOFLSH;
392 }
393
394 __pfast = 1;
395 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
396 TCSASOFT | TCSADRAIN : TCSADRAIN,
397 _cursesi_screen->curt) ? ERR : OK);
398 }
399
400 void
401 __startwin(SCREEN *screen)
402 {
403 /* static char *stdbuf;*/
404 /* static size_t len;*/
405
406 (void) fflush(screen->infd);
407
408 /*
409 * Some C libraries default to a 1K buffer when talking to a tty.
410 * With a larger screen, especially across a network, we'd like
411 * to get it to all flush in a single write. Make it twice as big
412 * as just the characters (so that we have room for cursor motions
413 * and attribute information) but no more than 8K.
414 */
415 if (screen->stdbuf == NULL) {
416 screen->len = LINES * COLS * 2;
417 if (screen->len > 8192)
418 screen->len = 8192;
419 if ((screen->stdbuf = malloc(screen->len)) == NULL)
420 screen->len = 0;
421 }
422 (void) setvbuf(screen->outfd, screen->stdbuf, _IOFBF, screen->len);
423
424 tputs(__tc_ti, 0, __cputchar);
425 tputs(__tc_vs, 0, __cputchar);
426 if (screen->curscr->flags & __KEYPAD)
427 tputs(__tc_ks, 0, __cputchar);
428 screen->endwin = 0;
429 }
430
431 int
432 endwin(void)
433 {
434 return __stopwin();
435 }
436
437 bool
438 isendwin(void)
439 {
440 return (_cursesi_screen->endwin ? TRUE : FALSE);
441 }
442
443 int
444 flushinp(void)
445 {
446 (void) fpurge(_cursesi_screen->infd);
447 return (OK);
448 }
449
450 /*
451 * The following routines, savetty and resetty are completely useless and
452 * are left in only as stubs. If people actually use them they will almost
453 * certainly screw up the state of the world.
454 */
455 /*static struct termios savedtty;*/
456 int
457 savetty(void)
458 {
459 return (tcgetattr(fileno(_cursesi_screen->infd),
460 &_cursesi_screen->savedtty) ? ERR : OK);
461 }
462
463 int
464 resetty(void)
465 {
466 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ?
467 TCSASOFT | TCSADRAIN : TCSADRAIN,
468 &_cursesi_screen->savedtty) ? ERR : OK);
469 }
470
471 /*
472 * erasechar --
473 * Return the character of the erase key.
474 *
475 */
476 char
477 erasechar(void)
478 {
479 return _cursesi_screen->baset.c_cc[VERASE];
480 }
481
482 /*
483 * killchar --
484 * Return the character of the kill key.
485 */
486 char
487 killchar(void)
488 {
489 return _cursesi_screen->baset.c_cc[VKILL];
490 }
491