1 /* term.c -- Routines for managing terminal I/O settings by Alan Cox.
2 * From LJ 17 */
3
4 /* Thanks to Dave Cook for rescuing it */
5
6 /* CHANGE LOG
7 * --------------------------------------------------------------------
8 * 28Apr03 dm include ioctl.h and declare void ctcinit();
9 */
10
11
12 #include <termios.h>
13 #ifndef __APPLE__
14 #include <asm/ioctls.h>
15 #endif
16 #include <sys/ioctl.h>
17 #include <signal.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <stdio.h>
21
22 void ctcinit(void);
23
24 /* This will be used for new terminal settings. */
25 static struct termios current;
26
27 /* This will hold the initial state so that we can restor it later. */
28 static struct termios initial;
29
30 /* Restor the termianl settings to those saved when term_init was called. */
term_restore(void)31 void term_restore(void)
32 {
33 tcsetattr(0, TCSANOW, &initial);
34 }
35
36 /* Clean up termianl; called on exit. */
term_exit(void)37 void term_exit(void)
38 {
39 term_restore();
40 }
41
42 /* Will be called when contrl-Z is pressed;
43 * this correctly handles the terminal. */
term_ctrlz(int i)44 void term_ctrlz(int i)
45 {
46 signal(SIGTSTP, term_ctrlz);
47 term_restore();
48 kill(getpid(), SIGSTOP);
49 }
50
51 /* Will be called when the application is continued
52 * after having been stopped. */
term_cont(int i)53 void term_cont(int i)
54 {
55 signal(SIGCONT, term_cont);
56 tcsetattr(0, TCSANOW, ¤t);
57 }
58
59 /* callback for SIGQUIT is different type from atexit callback */
term_quit(int i)60 void term_quit(int i)
61 {
62 term_exit();
63 }
64
65 /* Needs to be called to initialize the terminal. */
term_init(void)66 void term_init(void)
67 {
68 /* If stdin isn't a terminal this fails.
69 But then so does tcsetattr(), so it doesn't matter. */
70 tcgetattr(0, &initial);
71 /* Save a copy to work with later. */
72 current = initial;
73 /* We _must_ clean up when we exit. */
74 /* signal(SIGINT, term_exit); */
75 ctcinit(); /* XLisp wants to catch ctrl C */
76 signal(SIGQUIT, term_quit);
77 /* Control-Z must also be handled. */
78 signal(SIGTSTP, term_ctrlz);
79 signal(SIGCONT, term_cont);
80 atexit(term_exit);
81 }
82
83 /* Set character-by-character input mode. */
term_character(void)84 void term_character(void)
85 {
86 /* One or more characters are sufficient to cause a read return. */
87 current.c_cc[VMIN] = 1;
88 /* No timeout; read waits forever until ready. */
89 current.c_cc[VTIME] = 0;
90 /* Line-by-line mode off */
91 current.c_lflag &= ~ICANON;
92 #ifndef READ_LINE
93 current.c_lflag &= ~ECHO;
94 #endif
95 tcsetattr(0, TCSANOW, ¤t);
96 }
97
98 /* Return to line-by-line input mode. */
term_line(void)99 void term_line(void)
100 {
101 current.c_lflag |= ICANON;
102 tcsetattr(0, TCSANOW, ¤t);
103 }
104
105
106 #define ERROR(s) return (perror(s), -1)
107
108 /* term_testchar -- tell whether character is ready or not,
109 *
110 * if ready, return it, otherwise return -2
111 */
term_testchar(void)112 int term_testchar(void)
113 {
114 int n;
115 char c;
116
117 if (ioctl(0, FIONREAD, &n) < 0)
118 ERROR("IOgetchar");
119 if (n == 0) return -2;
120 switch(read(0, &c, 1)) {
121 case 1:
122 return c;
123 case 0:
124 return EOF;
125 default:
126 ERROR("IOgetchar-read");
127 }
128 }
129
130
131 /* term_getchar -- get a character (block if necessary) */
132 /**/
term_getchar(void)133 int term_getchar(void)
134 {
135 char c;
136 int rslt = read(0, &c, 1);
137 return (rslt == 1 ? c : EOF);
138 }
139
140