tty.c revision 1.43.24.1 1 /* $NetBSD: tty.c,v 1.43.24.1 2017/01/07 08:56:04 pgoyette 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.24.1 2017/01/07 08:56:04 pgoyette 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
78 baudrate(void)
79 {
80
81 if (_cursesi_screen->notty == TRUE)
82 return 0;
83
84 return cfgetospeed(&_cursesi_screen->baset);
85 }
86
87 /*
88 * gettmode --
89 * Do terminal type initialization.
90 */
91 int
92 gettmode(void)
93 {
94
95 if (_cursesi_gettmode(_cursesi_screen) == ERR)
96 return ERR;
97
98 __GT = _cursesi_screen->GT;
99 __NONL = _cursesi_screen->NONL;
100 return OK;
101 }
102
103 /*
104 * _cursesi_gettmode --
105 * Do the terminal type initialisation for the tty attached to the
106 * given screen.
107 */
108 int
109 _cursesi_gettmode(SCREEN *screen)
110 {
111 screen->useraw = 0;
112
113 if (tcgetattr(fileno(screen->infd), &screen->orig_termios)) {
114 /* if the input fd is not a tty try the output */
115 if (tcgetattr(fileno(screen->infd), &screen->orig_termios)) {
116 /* not a tty ... we will disable tty related stuff */
117 screen->notty = TRUE;
118 __GT = 0;
119 __NONL = 0;
120 return OK;
121 }
122 }
123
124 screen->baset = screen->orig_termios;
125 screen->baset.c_oflag &= ~OXTABS;
126
127 screen->GT = 0; /* historical. was used before we wired OXTABS off */
128 screen->NONL = (screen->baset.c_oflag & ONLCR) == 0;
129
130 /*
131 * XXX
132 * System V and SMI systems overload VMIN and VTIME, such that
133 * VMIN is the same as the VEOF element, and VTIME is the same
134 * as the VEOL element. This means that, if VEOF was ^D, the
135 * default VMIN is 4. Majorly stupid.
136 */
137 screen->cbreakt = screen->baset;
138 screen->cbreakt.c_lflag &= ~(ECHO | ECHONL | ICANON);
139 screen->cbreakt.c_cc[VMIN] = 1;
140 screen->cbreakt.c_cc[VTIME] = 0;
141
142 screen->rawt = screen->cbreakt;
143 screen->rawt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INLCR | IGNCR |
144 ICRNL | IXON);
145 screen->rawt.c_oflag &= ~OPOST;
146 screen->rawt.c_lflag &= ~(ISIG | IEXTEN);
147
148 #if TCSASOFT == 0
149 /*
150 * In general, curses should leave hardware-related settings alone.
151 * This includes parity and word size. Older versions set the tty
152 * to 8 bits, no parity in raw(), but this is considered to be an
153 * artifact of the old tty interface. If it's desired to change
154 * parity and word size, the TCSASOFT bit has to be removed from the
155 * calls that switch to/from "raw" mode.
156 */
157 screen->rawt.c_iflag &= ~ISTRIP;
158 screen->rawt.c_cflag &= ~(CSIZE | PARENB);
159 screen->rawt.c_cflag |= CS8;
160 #endif
161
162 screen->curt = &screen->baset;
163 return tcsetattr(fileno(screen->infd), TCSASOFT | TCSADRAIN,
164 screen->curt) ? ERR : OK;
165 }
166
167 /*
168 * raw --
169 * Put the terminal into raw mode
170 */
171 int
172 raw(void)
173 {
174 #ifdef DEBUG
175 __CTRACE(__CTRACE_MISC, "raw()\n");
176 #endif
177 /* Check if we need to restart ... */
178 if (_cursesi_screen->endwin)
179 __restartwin();
180
181 _cursesi_screen->useraw = __pfast = __rawmode = 1;
182 _cursesi_screen->curt = &_cursesi_screen->rawt;
183 if (_cursesi_screen->notty == TRUE)
184 return OK;
185 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
186 _cursesi_screen->curt) ? ERR : OK;
187 }
188
189 /*
190 * noraw --
191 * Put the terminal into cooked mode
192 */
193 int
194 noraw(void)
195 {
196 #ifdef DEBUG
197 __CTRACE(__CTRACE_MISC, "noraw()\n");
198 #endif
199 /* Check if we need to restart ... */
200 if (_cursesi_screen->endwin)
201 __restartwin();
202
203 _cursesi_screen->useraw = __pfast = __rawmode = 0;
204 if (_cursesi_screen->notty == TRUE)
205 return OK;
206 _cursesi_screen->curt = &_cursesi_screen->baset;
207 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
208 _cursesi_screen->curt) ? ERR : OK;
209 }
210
211 /*
212 * cbreak --
213 * Enable cbreak mode
214 */
215 int
216 cbreak(void)
217 {
218 #ifdef DEBUG
219 __CTRACE(__CTRACE_MISC, "cbreak()\n");
220 #endif
221 /* Check if we need to restart ... */
222 if (_cursesi_screen->endwin)
223 __restartwin();
224
225 __rawmode = 1;
226 if (_cursesi_screen->notty == TRUE)
227 return OK;
228 _cursesi_screen->curt = _cursesi_screen->useraw ?
229 &_cursesi_screen->rawt : &_cursesi_screen->cbreakt;
230 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
231 _cursesi_screen->curt) ? ERR : OK;
232 }
233
234 /*
235 * nocbreak --
236 * Disable cbreak mode
237 */
238 int
239 nocbreak(void)
240 {
241 #ifdef DEBUG
242 __CTRACE(__CTRACE_MISC, "nocbreak()\n");
243 #endif
244 /* Check if we need to restart ... */
245 if (_cursesi_screen->endwin)
246 __restartwin();
247
248 __rawmode = 0;
249 if (_cursesi_screen->notty == TRUE)
250 return OK;
251 /* if we were in halfdelay mode then nuke the timeout */
252 if ((_cursesi_screen->half_delay == TRUE) &&
253 (__notimeout() == ERR))
254 return ERR;
255
256 _cursesi_screen->half_delay = FALSE;
257 _cursesi_screen->curt = _cursesi_screen->useraw ?
258 &_cursesi_screen->rawt : &_cursesi_screen->baset;
259 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
260 _cursesi_screen->curt) ? ERR : OK;
261 }
262
263 /*
264 * halfdelay --
265 * Put the terminal into cbreak mode with the specified timeout.
266 *
267 */
268 int
269 halfdelay(int duration)
270 {
271 if ((duration < 1) || (duration > 255))
272 return ERR;
273
274 if (cbreak() == ERR)
275 return ERR;
276
277 if (__timeout(duration) == ERR)
278 return ERR;
279
280 _cursesi_screen->half_delay = TRUE;
281 return OK;
282 }
283
284 int
285 __delay(void)
286 {
287 #ifdef DEBUG
288 __CTRACE(__CTRACE_MISC, "__delay()\n");
289 #endif
290 /* Check if we need to restart ... */
291 if (_cursesi_screen->endwin)
292 __restartwin();
293
294 if (_cursesi_screen->notty == TRUE)
295 return OK;
296 _cursesi_screen->rawt.c_cc[VMIN] = 1;
297 _cursesi_screen->rawt.c_cc[VTIME] = 0;
298 _cursesi_screen->cbreakt.c_cc[VMIN] = 1;
299 _cursesi_screen->cbreakt.c_cc[VTIME] = 0;
300 _cursesi_screen->baset.c_cc[VMIN] = 1;
301 _cursesi_screen->baset.c_cc[VTIME] = 0;
302
303 if (tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW,
304 _cursesi_screen->curt)) {
305 __restore_termios();
306 return ERR;
307 }
308
309 return OK;
310 }
311
312 int
313 __nodelay(void)
314 {
315 #ifdef DEBUG
316 __CTRACE(__CTRACE_MISC, "__nodelay()\n");
317 #endif
318 /* Check if we need to restart ... */
319 if (_cursesi_screen->endwin)
320 __restartwin();
321
322 if (_cursesi_screen->notty == TRUE)
323 return OK;
324 _cursesi_screen->rawt.c_cc[VMIN] = 0;
325 _cursesi_screen->rawt.c_cc[VTIME] = 0;
326 _cursesi_screen->cbreakt.c_cc[VMIN] = 0;
327 _cursesi_screen->cbreakt.c_cc[VTIME] = 0;
328 _cursesi_screen->baset.c_cc[VMIN] = 0;
329 _cursesi_screen->baset.c_cc[VTIME] = 0;
330
331 if (tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW,
332 _cursesi_screen->curt)) {
333 __restore_termios();
334 return ERR;
335 }
336
337 return OK;
338 }
339
340 void
341 __save_termios(void)
342 {
343 /* Check if we need to restart ... */
344 if (_cursesi_screen->endwin)
345 __restartwin();
346
347 if (_cursesi_screen->notty == TRUE)
348 return;
349 _cursesi_screen->ovmin = _cursesi_screen->cbreakt.c_cc[VMIN];
350 _cursesi_screen->ovtime = _cursesi_screen->cbreakt.c_cc[VTIME];
351 }
352
353 void
354 __restore_termios(void)
355 {
356 /* Check if we need to restart ... */
357 if (_cursesi_screen->endwin)
358 __restartwin();
359
360 if (_cursesi_screen->notty == TRUE)
361 return;
362 _cursesi_screen->rawt.c_cc[VMIN] = _cursesi_screen->ovmin;
363 _cursesi_screen->rawt.c_cc[VTIME] = _cursesi_screen->ovtime;
364 _cursesi_screen->cbreakt.c_cc[VMIN] = _cursesi_screen->ovmin;
365 _cursesi_screen->cbreakt.c_cc[VTIME] = _cursesi_screen->ovtime;
366 _cursesi_screen->baset.c_cc[VMIN] = _cursesi_screen->ovmin;
367 _cursesi_screen->baset.c_cc[VTIME] = _cursesi_screen->ovtime;
368 }
369
370 int
371 __timeout(int delay)
372 {
373 #ifdef DEBUG
374 __CTRACE(__CTRACE_MISC, "__timeout()\n");
375 #endif
376 /* Check if we need to restart ... */
377 if (_cursesi_screen->endwin)
378 __restartwin();
379
380 if (_cursesi_screen->notty == TRUE)
381 return OK;
382 _cursesi_screen->ovmin = _cursesi_screen->cbreakt.c_cc[VMIN];
383 _cursesi_screen->ovtime = _cursesi_screen->cbreakt.c_cc[VTIME];
384 _cursesi_screen->rawt.c_cc[VMIN] = 0;
385 _cursesi_screen->rawt.c_cc[VTIME] = delay;
386 _cursesi_screen->cbreakt.c_cc[VMIN] = 0;
387 _cursesi_screen->cbreakt.c_cc[VTIME] = delay;
388 _cursesi_screen->baset.c_cc[VMIN] = 0;
389 _cursesi_screen->baset.c_cc[VTIME] = delay;
390
391 if (tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW,
392 _cursesi_screen->curt)) {
393 __restore_termios();
394 return ERR;
395 }
396
397 return OK;
398 }
399
400 int
401 __notimeout(void)
402 {
403 #ifdef DEBUG
404 __CTRACE(__CTRACE_MISC, "__notimeout()\n");
405 #endif
406 /* Check if we need to restart ... */
407 if (_cursesi_screen->endwin)
408 __restartwin();
409
410 if (_cursesi_screen->notty == TRUE)
411 return OK;
412 _cursesi_screen->rawt.c_cc[VMIN] = 1;
413 _cursesi_screen->rawt.c_cc[VTIME] = 0;
414 _cursesi_screen->cbreakt.c_cc[VMIN] = 1;
415 _cursesi_screen->cbreakt.c_cc[VTIME] = 0;
416 _cursesi_screen->baset.c_cc[VMIN] = 1;
417 _cursesi_screen->baset.c_cc[VTIME] = 0;
418
419 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW,
420 _cursesi_screen->curt) ? ERR : OK;
421 }
422
423 int
424 echo(void)
425 {
426 #ifdef DEBUG
427 __CTRACE(__CTRACE_MISC, "echo()\n");
428 #endif
429 /* Check if we need to restart ... */
430 if (_cursesi_screen->endwin)
431 __restartwin();
432
433 __echoit = 1;
434 return OK;
435 }
436
437 int
438 noecho(void)
439 {
440 #ifdef DEBUG
441 __CTRACE(__CTRACE_MISC, "noecho()\n");
442 #endif
443 /* Check if we need to restart ... */
444 if (_cursesi_screen->endwin)
445 __restartwin();
446
447 __echoit = 0;
448 return OK;
449 }
450
451 int
452 nl(void)
453 {
454 #ifdef DEBUG
455 __CTRACE(__CTRACE_MISC, "nl()\n");
456 #endif
457 /* Check if we need to restart ... */
458 if (_cursesi_screen->endwin)
459 __restartwin();
460
461 if (_cursesi_screen->notty == TRUE)
462 return OK;
463 _cursesi_screen->rawt.c_iflag |= ICRNL;
464 _cursesi_screen->rawt.c_oflag |= ONLCR;
465 _cursesi_screen->cbreakt.c_iflag |= ICRNL;
466 _cursesi_screen->cbreakt.c_oflag |= ONLCR;
467 _cursesi_screen->baset.c_iflag |= ICRNL;
468 _cursesi_screen->baset.c_oflag |= ONLCR;
469
470 _cursesi_screen->nl = 1;
471 _cursesi_screen->pfast = _cursesi_screen->rawmode;
472 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
473 _cursesi_screen->curt) ? ERR : OK;
474 }
475
476 int
477 nonl(void)
478 {
479 #ifdef DEBUG
480 __CTRACE(__CTRACE_MISC, "nonl()\n");
481 #endif
482 /* Check if we need to restart ... */
483 if (_cursesi_screen->endwin)
484 __restartwin();
485
486 if (_cursesi_screen->notty == TRUE)
487 return OK;
488 _cursesi_screen->rawt.c_iflag &= ~ICRNL;
489 _cursesi_screen->rawt.c_oflag &= ~ONLCR;
490 _cursesi_screen->cbreakt.c_iflag &= ~ICRNL;
491 _cursesi_screen->cbreakt.c_oflag &= ~ONLCR;
492 _cursesi_screen->baset.c_iflag &= ~ICRNL;
493 _cursesi_screen->baset.c_oflag &= ~ONLCR;
494
495 _cursesi_screen->nl = 0;
496 __pfast = 1;
497 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
498 _cursesi_screen->curt) ? ERR : OK;
499 }
500
501 #ifndef _CURSES_USE_MACROS
502 void
503 noqiflush(void)
504 {
505
506 (void)intrflush(stdscr, FALSE);
507 }
508
509 void
510 qiflush(void)
511 {
512
513 (void)intrflush(stdscr, TRUE);
514 }
515 #endif /* _CURSES_USE_MACROS */
516
517 /*ARGSUSED*/
518 int
519 intrflush(WINDOW *win, bool bf)
520 {
521 /* Check if we need to restart ... */
522 if (_cursesi_screen->endwin)
523 __restartwin();
524
525 if (_cursesi_screen->notty == TRUE)
526 return OK;
527 if (bf) {
528 _cursesi_screen->rawt.c_lflag &= ~NOFLSH;
529 _cursesi_screen->cbreakt.c_lflag &= ~NOFLSH;
530 _cursesi_screen->baset.c_lflag &= ~NOFLSH;
531 } else {
532 _cursesi_screen->rawt.c_lflag |= NOFLSH;
533 _cursesi_screen->cbreakt.c_lflag |= NOFLSH;
534 _cursesi_screen->baset.c_lflag |= NOFLSH;
535 }
536
537 __pfast = 1;
538 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
539 _cursesi_screen->curt) ? ERR : OK;
540 }
541
542 void
543 __startwin(SCREEN *screen)
544 {
545
546 (void)fflush(screen->infd);
547
548 /*
549 * Some C libraries default to a 1K buffer when talking to a tty.
550 * With a larger screen, especially across a network, we'd like
551 * to get it to all flush in a single write. Make it twice as big
552 * as just the characters (so that we have room for cursor motions
553 * and attribute information) but no more than 8K.
554 */
555 if (screen->stdbuf == NULL) {
556 screen->len = LINES * COLS * 2;
557 if (screen->len > 8192)
558 screen->len = 8192;
559 if ((screen->stdbuf = malloc(screen->len)) == NULL)
560 screen->len = 0;
561 }
562 (void)setvbuf(screen->outfd, screen->stdbuf, _IOFBF, screen->len);
563
564 ti_puts(screen->term, t_enter_ca_mode(screen->term), 0,
565 __cputchar_args, (void *) screen->outfd);
566 ti_puts(screen->term, t_cursor_normal(screen->term), 0,
567 __cputchar_args, (void *) screen->outfd);
568 if (screen->curscr->flags & __KEYPAD)
569 ti_puts(screen->term, t_keypad_xmit(screen->term), 0,
570 __cputchar_args, (void *) screen->outfd);
571 screen->endwin = 0;
572 }
573
574 int
575 endwin(void)
576 {
577 #ifdef DEBUG
578 __CTRACE(__CTRACE_MISC, "endwin\n");
579 #endif
580 return __stopwin();
581 }
582
583 bool
584 isendwin(void)
585 {
586
587 return _cursesi_screen->endwin ? TRUE : FALSE;
588 }
589
590 int
591 flushinp(void)
592 {
593
594 (void)fpurge(_cursesi_screen->infd);
595 return OK;
596 }
597
598 /*
599 * The following routines, savetty and resetty are completely useless and
600 * are left in only as stubs. If people actually use them they will almost
601 * certainly screw up the state of the world.
602 */
603 /*static struct termios savedtty;*/
604 int
605 savetty(void)
606 {
607
608 if (_cursesi_screen->notty == TRUE)
609 return OK;
610 return tcgetattr(fileno(_cursesi_screen->infd),
611 &_cursesi_screen->savedtty) ? ERR : OK;
612 }
613
614 int
615 resetty(void)
616 {
617
618 if (_cursesi_screen->notty == TRUE)
619 return OK;
620 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
621 &_cursesi_screen->savedtty) ? ERR : OK;
622 }
623
624 /*
625 * erasechar --
626 * Return the character of the erase key.
627 */
628 char
629 erasechar(void)
630 {
631
632 if (_cursesi_screen->notty == TRUE)
633 return 0;
634 return _cursesi_screen->baset.c_cc[VERASE];
635 }
636
637 /*
638 * killchar --
639 * Return the character of the kill key.
640 */
641 char
642 killchar(void)
643 {
644
645 if (_cursesi_screen->notty == TRUE)
646 return 0;
647 return _cursesi_screen->baset.c_cc[VKILL];
648 }
649
650 /*
651 * erasewchar --
652 * Return the wide character of the erase key.
653 */
654 int
655 erasewchar(wchar_t *ch)
656 {
657
658 #ifndef HAVE_WCHAR
659 return ERR;
660 #else
661 if (_cursesi_screen->notty == TRUE)
662 return ERR;
663 *ch = _cursesi_screen->baset.c_cc[VERASE];
664 return OK;
665 #endif /* HAVE_WCHAR */
666 }
667
668 /*
669 * killwchar --
670 * Return the wide character of the kill key.
671 */
672 int
673 killwchar( wchar_t *ch )
674 {
675
676 #ifndef HAVE_WCHAR
677 return ERR;
678 #else
679 if (_cursesi_screen->notty == TRUE)
680 return 0;
681 *ch = _cursesi_screen->baset.c_cc[VKILL];
682 return OK;
683 #endif /* HAVE_WCHAR */
684 }
685
686 int
687 typeahead(int filedes)
688 {
689
690 _cursesi_screen->checkfd = filedes;
691 return OK;
692 }
693