]> pd.if.org Git - pd_readline/blob - mg/ttyio.c
Added mg from an OpenBSD mirror site. Many thanks to the OpenBSD team and the mg...
[pd_readline] / mg / ttyio.c
1 /*      $OpenBSD: ttyio.c,v 1.32 2008/02/05 12:53:38 reyk Exp $ */
2
3 /* This file is in the public domain. */
4
5 /*
6  * POSIX terminal I/O.
7  *
8  * The functions in this file negotiate with the operating system for
9  * keyboard characters, and write characters to the display in a barely
10  * buffered fashion.
11  */
12 #include "def.h"
13
14 #include <sys/types.h>
15 #include <sys/time.h>
16 #include <sys/ioctl.h>
17 #include <fcntl.h>
18 #include <termios.h>
19 #include <term.h>
20
21 #define NOBUF   512                     /* Output buffer size. */
22
23 #ifndef TCSASOFT
24 #define TCSASOFT        0
25 #endif
26
27 int     ttstarted;
28 char    obuf[NOBUF];                    /* Output buffer. */
29 size_t  nobuf;                          /* Buffer count. */
30 struct  termios oldtty;                 /* POSIX tty settings. */
31 struct  termios newtty;
32 int     nrow;                           /* Terminal size, rows. */
33 int     ncol;                           /* Terminal size, columns. */
34
35 /*
36  * This function gets called once, to set up the terminal.
37  * On systems w/o TCSASOFT we turn off off flow control,
38  * which isn't really the right thing to do.
39  */
40 void
41 ttopen(void)
42 {
43         if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO))
44                 panic("standard input and output must be a terminal");
45
46         if (ttraw() == FALSE)
47                 panic("aborting due to terminal initialize failure");
48 }
49
50 /*
51  * This function sets the terminal to RAW mode, as defined for the current
52  * shell.  This is called both by ttopen() above and by spawncli() to
53  * get the current terminal settings and then change them to what
54  * mg expects.  Thus, tty changes done while spawncli() is in effect
55  * will be reflected in mg.
56  */
57 int
58 ttraw(void)
59 {
60         if (tcgetattr(0, &oldtty) < 0) {
61                 ewprintf("ttopen can't get terminal attributes");
62                 return (FALSE);
63         }
64         (void)memcpy(&newtty, &oldtty, sizeof(newtty));
65         /* Set terminal to 'raw' mode and ignore a 'break' */
66         newtty.c_cc[VMIN] = 1;
67         newtty.c_cc[VTIME] = 0;
68         newtty.c_iflag |= IGNBRK;
69         newtty.c_iflag &= ~(BRKINT | PARMRK | INLCR | IGNCR | ICRNL | IXON);
70         newtty.c_oflag &= ~OPOST;
71         newtty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
72
73 #if !TCSASOFT
74         /*
75          * If we don't have TCSASOFT, force terminal to
76          * 8 bits, no parity.
77          */
78         newtty.c_iflag &= ~ISTRIP;
79         newtty.c_cflag &= ~(CSIZE | PARENB);
80         newtty.c_cflag |= CS8;
81 #endif
82         if (tcsetattr(0, TCSASOFT | TCSADRAIN, &newtty) < 0) {
83                 ewprintf("ttopen can't tcsetattr");
84                 return (FALSE);
85         }
86         ttstarted = 1;
87
88         return (TRUE);
89 }
90
91 /*
92  * This function gets called just before we go back home to the shell.
93  * Put all of the terminal parameters back.
94  * Under UN*X this just calls ttcooked(), but the ttclose() hook is in
95  * because vttidy() in display.c expects it for portability reasons.
96  */
97 void
98 ttclose(void)
99 {
100         if (ttstarted) {
101                 if (ttcooked() == FALSE)
102                         panic("");      /* ttcooked() already printf'd */
103                 ttstarted = 0;
104         }
105 }
106
107 /*
108  * This function restores all terminal settings to their default values,
109  * in anticipation of exiting or suspending the editor.
110  */
111 int
112 ttcooked(void)
113 {
114         ttflush();
115         if (tcsetattr(0, TCSASOFT | TCSADRAIN, &oldtty) < 0) {
116                 ewprintf("ttclose can't tcsetattr");
117                 return (FALSE);
118         }
119         return (TRUE);
120 }
121
122 /*
123  * Write character to the display.  Characters are buffered up,
124  * to make things a little bit more efficient.
125  */
126 int
127 ttputc(int c)
128 {
129         if (nobuf >= NOBUF)
130                 ttflush();
131         obuf[nobuf++] = c;
132         return (c);
133 }
134
135 /*
136  * Flush output.
137  */
138 void
139 ttflush(void)
140 {
141         ssize_t  written;
142         char    *buf = obuf;
143
144         if (nobuf == 0)
145                 return;
146
147         while ((written = write(fileno(stdout), buf, nobuf)) != nobuf) {
148                 if (written == -1) {
149                         if (errno == EINTR)
150                                 continue;
151                         panic("ttflush write failed");
152                 }
153                 buf += written;
154                 nobuf -= written;
155         }
156         nobuf = 0;
157 }
158
159 /*
160  * Read character from terminal. All 8 bits are returned, so that you
161  * can use a multi-national terminal.
162  */
163 int
164 ttgetc(void)
165 {
166         char    c;
167         ssize_t ret;
168
169         do {
170                 ret = read(STDIN_FILENO, &c, 1);
171                 if (ret == -1 && errno == EINTR) {
172                         if (winch_flag) {
173                                 redraw(0, 0);
174                                 winch_flag = 0;
175                         }
176                 } else if (ret == 1)
177                         break;
178         } while (1);
179         return ((int) c) & 0xFF;
180 }
181
182 /*
183  * Returns TRUE if there are characters waiting to be read.
184  */
185 int
186 charswaiting(void)
187 {
188         int     x;
189
190         return ((ioctl(0, FIONREAD, &x) < 0) ? 0 : x);
191 }
192
193 /*
194  * panic - just exit, as quickly as we can.
195  */
196 void
197 panic(char *s)
198 {
199         ttclose();
200         (void) fputs("panic: ", stderr);
201         (void) fputs(s, stderr);
202         (void) fputc('\n', stderr);
203         exit(1);
204 }
205
206 /*
207  * This function returns FALSE if any characters have showed up on the
208  * tty before 'msec' milliseconds.
209  */
210 int
211 ttwait(int msec)
212 {
213         fd_set          readfds;
214         struct timeval  tmout;
215
216         FD_ZERO(&readfds);
217         FD_SET(0, &readfds);
218
219         tmout.tv_sec = msec/1000;
220         tmout.tv_usec = msec - tmout.tv_sec * 1000;
221
222         if ((select(1, &readfds, NULL, NULL, &tmout)) == 0)
223                 return (TRUE);
224         return (FALSE);
225 }