1 /* $NetBSD: tty.c,v 1.43 2011/08/29 11:07:38 christos 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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)tty.c 8.6 (Berkeley) 1/10/95";
36 #else
37 __RCSID("$NetBSD: tty.c,v 1.43 2011/08/29 11:07:38 christos Exp $");
38 #endif
39 #endif /* not lint */
40
41 #include <sys/types.h>
42
43 #include <stdlib.h>
44 #include <termios.h>
45 #include <unistd.h>
46 #include <sys/fcntl.h>
47 #include <sys/ioctl.h>
48
49 #include "curses.h"
50 #include "curses_private.h"
51
52 /*
53 * In general, curses should leave tty hardware settings alone (speed, parity,
54 * word size). This is most easily done in BSD by using TCSASOFT on all
55 * tcsetattr calls. On other systems, it would be better to get and restore
56 * those attributes at each change, or at least when stopped and restarted.
57 * See also the comments in getterm().
58 */
59 #ifndef TCSASOFT
60 #define TCSASOFT 0
61 #endif
62
63 int __tcaction = TCSASOFT != 0; /* Ignore hardware settings */
64
65 #ifndef OXTABS
66 #ifdef XTABS /* SMI uses XTABS. */
67 #define OXTABS XTABS
68 #else
69 #define OXTABS 0
70 #endif
71 #endif
72
73 /*
74 * baudrate --
75 * Return the current baudrate
76 */
77 int
baudrate(void)78 baudrate(void)
79 {
80 if (_cursesi_screen->notty == TRUE)
81 return 0;
82
83 return cfgetospeed(&_cursesi_screen->baset);
84 }
85
86 /*
87 * gettmode --
88 * Do terminal type initialization.
89 */
90 int
gettmode(void)91 gettmode(void)
92 {
93 if (_cursesi_gettmode(_cursesi_screen) == ERR)
94 return ERR;
95
96 __GT = _cursesi_screen->GT;
97 __NONL = _cursesi_screen->NONL;
98 return OK;
99 }
100
101 /*
102 * _cursesi_gettmode --
103 * Do the terminal type initialisation for the tty attached to the
104 * given screen.
105 */
106 int
_cursesi_gettmode(SCREEN * screen)107 _cursesi_gettmode(SCREEN *screen)
108 {
109 screen->useraw = 0;
110
111 if (tcgetattr(fileno(screen->infd), &screen->orig_termios)) {
112 /* if the input fd is not a tty try the output */
113 if (tcgetattr(fileno(screen->infd), &screen->orig_termios)) {
114 /* not a tty ... we will disable tty related stuff */
115 screen->notty = TRUE;
116 __GT = 0;
117 __NONL = 0;
118 return OK;
119 }
120 }
121
122 screen->baset = screen->orig_termios;
123 screen->baset.c_oflag &= ~OXTABS;
124
125 screen->GT = 0; /* historical. was used before we wired OXTABS off */
126 screen->NONL = (screen->baset.c_oflag & ONLCR) == 0;
127
128 /*
129 * XXX
130 * System V and SMI systems overload VMIN and VTIME, such that
131 * VMIN is the same as the VEOF element, and VTIME is the same
132 * as the VEOL element. This means that, if VEOF was ^D, the
133 * default VMIN is 4. Majorly stupid.
134 */
135 screen->cbreakt = screen->baset;
136 screen->cbreakt.c_lflag &= ~(ECHO | ECHONL | ICANON);
137 screen->cbreakt.c_cc[VMIN] = 1;
138 screen->cbreakt.c_cc[VTIME] = 0;
139
140 screen->rawt = screen->cbreakt;
141 screen->rawt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INLCR | IGNCR |
142 ICRNL | IXON);
143 screen->rawt.c_oflag &= ~OPOST;
144 screen->rawt.c_lflag &= ~(ISIG | IEXTEN);
145
146 #if TCSASOFT == 0
147 /*
148 * In general, curses should leave hardware-related settings alone.
149 * This includes parity and word size. Older versions set the tty
150 * to 8 bits, no parity in raw(), but this is considered to be an
151 * artifact of the old tty interface. If it's desired to change
152 * parity and word size, the TCSASOFT bit has to be removed from the
153 * calls that switch to/from "raw" mode.
154 */
155 screen->rawt.c_iflag &= ~ISTRIP;
156 screen->rawt.c_cflag &= ~(CSIZE | PARENB);
157 screen->rawt.c_cflag |= CS8;
158 #endif
159
160 screen->curt = &screen->baset;
161 return tcsetattr(fileno(screen->infd), TCSASOFT | TCSADRAIN,
162 screen->curt) ? ERR : OK;
163 }
164
165 /*
166 * raw --
167 * Put the terminal into raw mode
168 */
169 int
raw(void)170 raw(void)
171 {
172 #ifdef DEBUG
173 __CTRACE(__CTRACE_MISC, "raw()\n");
174 #endif
175 /* Check if we need to restart ... */
176 if (_cursesi_screen->endwin)
177 __restartwin();
178
179 _cursesi_screen->useraw = __pfast = __rawmode = 1;
180 _cursesi_screen->curt = &_cursesi_screen->rawt;
181 if (_cursesi_screen->notty == TRUE)
182 return OK;
183 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
184 _cursesi_screen->curt) ? ERR : OK;
185 }
186
187 /*
188 * noraw --
189 * Put the terminal into cooked mode
190 */
191 int
noraw(void)192 noraw(void)
193 {
194 #ifdef DEBUG
195 __CTRACE(__CTRACE_MISC, "noraw()\n");
196 #endif
197 /* Check if we need to restart ... */
198 if (_cursesi_screen->endwin)
199 __restartwin();
200
201 _cursesi_screen->useraw = __pfast = __rawmode = 0;
202 if (_cursesi_screen->notty == TRUE)
203 return OK;
204 _cursesi_screen->curt = &_cursesi_screen->baset;
205 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
206 _cursesi_screen->curt) ? ERR : OK;
207 }
208
209 /*
210 * cbreak --
211 * Enable cbreak mode
212 */
213 int
cbreak(void)214 cbreak(void)
215 {
216 #ifdef DEBUG
217 __CTRACE(__CTRACE_MISC, "cbreak()\n");
218 #endif
219 /* Check if we need to restart ... */
220 if (_cursesi_screen->endwin)
221 __restartwin();
222
223 __rawmode = 1;
224 if (_cursesi_screen->notty == TRUE)
225 return OK;
226 _cursesi_screen->curt = _cursesi_screen->useraw ?
227 &_cursesi_screen->rawt : &_cursesi_screen->cbreakt;
228 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
229 _cursesi_screen->curt) ? ERR : OK;
230 }
231
232 /*
233 * nocbreak --
234 * Disable cbreak mode
235 */
236 int
nocbreak(void)237 nocbreak(void)
238 {
239 #ifdef DEBUG
240 __CTRACE(__CTRACE_MISC, "nocbreak()\n");
241 #endif
242 /* Check if we need to restart ... */
243 if (_cursesi_screen->endwin)
244 __restartwin();
245
246 __rawmode = 0;
247 if (_cursesi_screen->notty == TRUE)
248 return OK;
249 /* if we were in halfdelay mode then nuke the timeout */
250 if ((_cursesi_screen->half_delay == TRUE) &&
251 (__notimeout() == ERR))
252 return ERR;
253
254 _cursesi_screen->half_delay = FALSE;
255 _cursesi_screen->curt = _cursesi_screen->useraw ?
256 &_cursesi_screen->rawt : &_cursesi_screen->baset;
257 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
258 _cursesi_screen->curt) ? ERR : OK;
259 }
260
261 /*
262 * halfdelay --
263 * Put the terminal into cbreak mode with the specified timeout.
264 *
265 */
266 int
halfdelay(int duration)267 halfdelay(int duration)
268 {
269 if ((duration < 1) || (duration > 255))
270 return ERR;
271
272 if (cbreak() == ERR)
273 return ERR;
274
275 if (__timeout(duration) == ERR)
276 return ERR;
277
278 _cursesi_screen->half_delay = TRUE;
279 return OK;
280 }
281
282 int
__delay(void)283 __delay(void)
284 {
285 #ifdef DEBUG
286 __CTRACE(__CTRACE_MISC, "__delay()\n");
287 #endif
288 /* Check if we need to restart ... */
289 if (_cursesi_screen->endwin)
290 __restartwin();
291
292 if (_cursesi_screen->notty == TRUE)
293 return OK;
294 _cursesi_screen->rawt.c_cc[VMIN] = 1;
295 _cursesi_screen->rawt.c_cc[VTIME] = 0;
296 _cursesi_screen->cbreakt.c_cc[VMIN] = 1;
297 _cursesi_screen->cbreakt.c_cc[VTIME] = 0;
298 _cursesi_screen->baset.c_cc[VMIN] = 1;
299 _cursesi_screen->baset.c_cc[VTIME] = 0;
300
301 if (tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW,
302 _cursesi_screen->curt)) {
303 __restore_termios();
304 return ERR;
305 }
306
307 return OK;
308 }
309
310 int
__nodelay(void)311 __nodelay(void)
312 {
313 #ifdef DEBUG
314 __CTRACE(__CTRACE_MISC, "__nodelay()\n");
315 #endif
316 /* Check if we need to restart ... */
317 if (_cursesi_screen->endwin)
318 __restartwin();
319
320 if (_cursesi_screen->notty == TRUE)
321 return OK;
322 _cursesi_screen->rawt.c_cc[VMIN] = 0;
323 _cursesi_screen->rawt.c_cc[VTIME] = 0;
324 _cursesi_screen->cbreakt.c_cc[VMIN] = 0;
325 _cursesi_screen->cbreakt.c_cc[VTIME] = 0;
326 _cursesi_screen->baset.c_cc[VMIN] = 0;
327 _cursesi_screen->baset.c_cc[VTIME] = 0;
328
329 if (tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW,
330 _cursesi_screen->curt)) {
331 __restore_termios();
332 return ERR;
333 }
334
335 return OK;
336 }
337
338 void
__save_termios(void)339 __save_termios(void)
340 {
341 /* Check if we need to restart ... */
342 if (_cursesi_screen->endwin)
343 __restartwin();
344
345 if (_cursesi_screen->notty == TRUE)
346 return;
347 _cursesi_screen->ovmin = _cursesi_screen->cbreakt.c_cc[VMIN];
348 _cursesi_screen->ovtime = _cursesi_screen->cbreakt.c_cc[VTIME];
349 }
350
351 void
__restore_termios(void)352 __restore_termios(void)
353 {
354 /* Check if we need to restart ... */
355 if (_cursesi_screen->endwin)
356 __restartwin();
357
358 if (_cursesi_screen->notty == TRUE)
359 return;
360 _cursesi_screen->rawt.c_cc[VMIN] = _cursesi_screen->ovmin;
361 _cursesi_screen->rawt.c_cc[VTIME] = _cursesi_screen->ovtime;
362 _cursesi_screen->cbreakt.c_cc[VMIN] = _cursesi_screen->ovmin;
363 _cursesi_screen->cbreakt.c_cc[VTIME] = _cursesi_screen->ovtime;
364 _cursesi_screen->baset.c_cc[VMIN] = _cursesi_screen->ovmin;
365 _cursesi_screen->baset.c_cc[VTIME] = _cursesi_screen->ovtime;
366 }
367
368 int
__timeout(int delay)369 __timeout(int delay)
370 {
371 #ifdef DEBUG
372 __CTRACE(__CTRACE_MISC, "__timeout()\n");
373 #endif
374 /* Check if we need to restart ... */
375 if (_cursesi_screen->endwin)
376 __restartwin();
377
378 if (_cursesi_screen->notty == TRUE)
379 return OK;
380 _cursesi_screen->ovmin = _cursesi_screen->cbreakt.c_cc[VMIN];
381 _cursesi_screen->ovtime = _cursesi_screen->cbreakt.c_cc[VTIME];
382 _cursesi_screen->rawt.c_cc[VMIN] = 0;
383 _cursesi_screen->rawt.c_cc[VTIME] = delay;
384 _cursesi_screen->cbreakt.c_cc[VMIN] = 0;
385 _cursesi_screen->cbreakt.c_cc[VTIME] = delay;
386 _cursesi_screen->baset.c_cc[VMIN] = 0;
387 _cursesi_screen->baset.c_cc[VTIME] = delay;
388
389 if (tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW,
390 _cursesi_screen->curt)) {
391 __restore_termios();
392 return ERR;
393 }
394
395 return OK;
396 }
397
398 int
__notimeout(void)399 __notimeout(void)
400 {
401 #ifdef DEBUG
402 __CTRACE(__CTRACE_MISC, "__notimeout()\n");
403 #endif
404 /* Check if we need to restart ... */
405 if (_cursesi_screen->endwin)
406 __restartwin();
407
408 if (_cursesi_screen->notty == TRUE)
409 return OK;
410 _cursesi_screen->rawt.c_cc[VMIN] = 1;
411 _cursesi_screen->rawt.c_cc[VTIME] = 0;
412 _cursesi_screen->cbreakt.c_cc[VMIN] = 1;
413 _cursesi_screen->cbreakt.c_cc[VTIME] = 0;
414 _cursesi_screen->baset.c_cc[VMIN] = 1;
415 _cursesi_screen->baset.c_cc[VTIME] = 0;
416
417 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW,
418 _cursesi_screen->curt) ? ERR : OK;
419 }
420
421 int
echo(void)422 echo(void)
423 {
424 #ifdef DEBUG
425 __CTRACE(__CTRACE_MISC, "echo()\n");
426 #endif
427 /* Check if we need to restart ... */
428 if (_cursesi_screen->endwin)
429 __restartwin();
430
431 __echoit = 1;
432 return OK;
433 }
434
435 int
noecho(void)436 noecho(void)
437 {
438 #ifdef DEBUG
439 __CTRACE(__CTRACE_MISC, "noecho()\n");
440 #endif
441 /* Check if we need to restart ... */
442 if (_cursesi_screen->endwin)
443 __restartwin();
444
445 __echoit = 0;
446 return OK;
447 }
448
449 int
nl(void)450 nl(void)
451 {
452 #ifdef DEBUG
453 __CTRACE(__CTRACE_MISC, "nl()\n");
454 #endif
455 /* Check if we need to restart ... */
456 if (_cursesi_screen->endwin)
457 __restartwin();
458
459 if (_cursesi_screen->notty == TRUE)
460 return OK;
461 _cursesi_screen->rawt.c_iflag |= ICRNL;
462 _cursesi_screen->rawt.c_oflag |= ONLCR;
463 _cursesi_screen->cbreakt.c_iflag |= ICRNL;
464 _cursesi_screen->cbreakt.c_oflag |= ONLCR;
465 _cursesi_screen->baset.c_iflag |= ICRNL;
466 _cursesi_screen->baset.c_oflag |= ONLCR;
467
468 _cursesi_screen->nl = 1;
469 _cursesi_screen->pfast = _cursesi_screen->rawmode;
470 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
471 _cursesi_screen->curt) ? ERR : OK;
472 }
473
474 int
nonl(void)475 nonl(void)
476 {
477 #ifdef DEBUG
478 __CTRACE(__CTRACE_MISC, "nonl()\n");
479 #endif
480 /* Check if we need to restart ... */
481 if (_cursesi_screen->endwin)
482 __restartwin();
483
484 if (_cursesi_screen->notty == TRUE)
485 return OK;
486 _cursesi_screen->rawt.c_iflag &= ~ICRNL;
487 _cursesi_screen->rawt.c_oflag &= ~ONLCR;
488 _cursesi_screen->cbreakt.c_iflag &= ~ICRNL;
489 _cursesi_screen->cbreakt.c_oflag &= ~ONLCR;
490 _cursesi_screen->baset.c_iflag &= ~ICRNL;
491 _cursesi_screen->baset.c_oflag &= ~ONLCR;
492
493 _cursesi_screen->nl = 0;
494 __pfast = 1;
495 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
496 _cursesi_screen->curt) ? ERR : OK;
497 }
498
499 #ifndef _CURSES_USE_MACROS
500 void
noqiflush(void)501 noqiflush(void)
502 {
503 (void) intrflush(stdscr, FALSE);
504 }
505
506 void
qiflush(void)507 qiflush(void)
508 {
509 (void) intrflush(stdscr, TRUE);
510 }
511 #endif /* _CURSES_USE_MACROS */
512
513 int
intrflush(WINDOW * win,bool bf)514 intrflush(WINDOW *win, bool bf) /*ARGSUSED*/
515 {
516 /* Check if we need to restart ... */
517 if (_cursesi_screen->endwin)
518 __restartwin();
519
520 if (_cursesi_screen->notty == TRUE)
521 return OK;
522 if (bf) {
523 _cursesi_screen->rawt.c_lflag &= ~NOFLSH;
524 _cursesi_screen->cbreakt.c_lflag &= ~NOFLSH;
525 _cursesi_screen->baset.c_lflag &= ~NOFLSH;
526 } else {
527 _cursesi_screen->rawt.c_lflag |= NOFLSH;
528 _cursesi_screen->cbreakt.c_lflag |= NOFLSH;
529 _cursesi_screen->baset.c_lflag |= NOFLSH;
530 }
531
532 __pfast = 1;
533 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
534 _cursesi_screen->curt) ? ERR : OK;
535 }
536
537 void
__startwin(SCREEN * screen)538 __startwin(SCREEN *screen)
539 {
540
541 (void) fflush(screen->infd);
542
543 /*
544 * Some C libraries default to a 1K buffer when talking to a tty.
545 * With a larger screen, especially across a network, we'd like
546 * to get it to all flush in a single write. Make it twice as big
547 * as just the characters (so that we have room for cursor motions
548 * and attribute information) but no more than 8K.
549 */
550 if (screen->stdbuf == NULL) {
551 screen->len = LINES * COLS * 2;
552 if (screen->len > 8192)
553 screen->len = 8192;
554 if ((screen->stdbuf = malloc(screen->len)) == NULL)
555 screen->len = 0;
556 }
557 (void) setvbuf(screen->outfd, screen->stdbuf, _IOFBF, screen->len);
558
559 ti_puts(screen->term, t_enter_ca_mode(screen->term), 0,
560 __cputchar_args, (void *) screen->outfd);
561 ti_puts(screen->term, t_cursor_normal(screen->term), 0,
562 __cputchar_args, (void *) screen->outfd);
563 if (screen->curscr->flags & __KEYPAD)
564 ti_puts(screen->term, t_keypad_xmit(screen->term), 0,
565 __cputchar_args, (void *) screen->outfd);
566 screen->endwin = 0;
567 }
568
569 int
endwin(void)570 endwin(void)
571 {
572 #ifdef DEBUG
573 __CTRACE(__CTRACE_MISC, "endwin\n");
574 #endif
575 return __stopwin();
576 }
577
578 bool
isendwin(void)579 isendwin(void)
580 {
581 return _cursesi_screen->endwin ? TRUE : FALSE;
582 }
583
584 int
flushinp(void)585 flushinp(void)
586 {
587 (void) fpurge(_cursesi_screen->infd);
588 return OK;
589 }
590
591 /*
592 * The following routines, savetty and resetty are completely useless and
593 * are left in only as stubs. If people actually use them they will almost
594 * certainly screw up the state of the world.
595 */
596 /*static struct termios savedtty;*/
597 int
savetty(void)598 savetty(void)
599 {
600 if (_cursesi_screen->notty == TRUE)
601 return OK;
602 return tcgetattr(fileno(_cursesi_screen->infd),
603 &_cursesi_screen->savedtty) ? ERR : OK;
604 }
605
606 int
resetty(void)607 resetty(void)
608 {
609 if (_cursesi_screen->notty == TRUE)
610 return OK;
611 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
612 &_cursesi_screen->savedtty) ? ERR : OK;
613 }
614
615 /*
616 * erasechar --
617 * Return the character of the erase key.
618 */
619 char
erasechar(void)620 erasechar(void)
621 {
622 if (_cursesi_screen->notty == TRUE)
623 return 0;
624 return _cursesi_screen->baset.c_cc[VERASE];
625 }
626
627 /*
628 * killchar --
629 * Return the character of the kill key.
630 */
631 char
killchar(void)632 killchar(void)
633 {
634 if (_cursesi_screen->notty == TRUE)
635 return 0;
636 return _cursesi_screen->baset.c_cc[VKILL];
637 }
638
639 /*
640 * erasewchar --
641 * Return the wide character of the erase key.
642 */
643 int
erasewchar(wchar_t * ch)644 erasewchar( wchar_t *ch )
645 {
646 #ifndef HAVE_WCHAR
647 return ERR;
648 #else
649 if (_cursesi_screen->notty == TRUE)
650 return ERR;
651 *ch = _cursesi_screen->baset.c_cc[VERASE];
652 return OK;
653 #endif /* HAVE_WCHAR */
654 }
655
656 /*
657 * killwchar --
658 * Return the wide character of the kill key.
659 */
660 int
killwchar(wchar_t * ch)661 killwchar( wchar_t *ch )
662 {
663 #ifndef HAVE_WCHAR
664 return ERR;
665 #else
666 if (_cursesi_screen->notty == TRUE)
667 return 0;
668 *ch = _cursesi_screen->baset.c_cc[VKILL];
669 return OK;
670 #endif /* HAVE_WCHAR */
671 }
672