1 /*
2 * The functions in this file negotiate with the operating system for
3 * characters, and write characters in a barely buffered fashion on the display.
4 * All operating systems.
5 */
6
7 #include <sys/types.h> /* 1.13 */
8
9 #ifdef UNIX /* System V */
10
11 #if defined(__GLIBC__) || \
12 defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
13 #define TERMIOS 1
14 #endif
15
16 #include <unistd.h>
17 #include <errno.h>
18 #include <stdio.h>
19 #include <signal.h>
20 #if defined(BSD) && !defined(TERMIOS)
21 #include <sys/ioctl.h>
22 #else
23 #ifdef OS2
24 #ifndef __EMX__
25 #define INCL_NOPM
26 #define INCL_DOS
27 #define INCL_KBD
28 #include <os2.h>
29 #endif
30 #include <io.h>
31 #else
32 #ifdef MINIX
33 #include <sgtty.h>
34 #define O_NDELAY O_NONBLOCK
35 #else
36 #ifdef TERMIOS
37 #include <sys/ioctl.h>
38 #include <termios.h>
39 #else
40 #include <termio.h>
41 #endif /* __GLIBC__ */
42 #endif /* MINIX */
43 #endif /* OS2 */
44 #endif /* BSD */
45 #include <errno.h>
46 #include <fcntl.h>
47 #include "def.h"
48 int kbdflgs; /* saved keyboard fd flags */
49 int kbdpoll; /* in O_NDELAY mode */
50 int kbdqp; /* there is a char in kbdq */
51 char kbdq; /* char we've already read */
52
53 #if defined(BSD) && !defined(TERMIOS)
54 struct sgttyb otermb;
55 struct sgttyb ntermb;
56 #else
57 #ifdef OS2
58 #ifndef __EMX__
59 KBDINFO kbst, kbst_std;
60 #endif
61 #else
62 #ifdef MINIX
63 struct sgttyb otermio; /* original terminal characteristics */
64 struct sgttyb ntermio; /* charactoristics to use inside */
65 struct tchars tchars, tcharsorig;
66 #else
67 #ifdef TERMIOS
68 #include <sys/ioctl.h>
69 struct termios otermio;
70 struct termios ntermio;
71 #else
72 struct termio otermio; /* original terminal characteristics */
73 struct termio ntermio; /* charactoristics to use inside */
74 #endif /* __GLIBC__ */
75 #endif /* MINIX */
76 #endif /* OS2 */
77 #endif /* BSD */
78
79 #ifndef OS2
80 //extern errno; /* System error number -- Necessary when compiling in BSD 1.13 */
81 #endif
82
83 int nrow; /* Terminal size, rows. */
84 int ncol; /* Terminal size, columns. */
85
86 /*
87 * This function is called once to set up the terminal device streams.
88 * On VMS, it translates TT until it finds the terminal, then assigns
89 * a channel to it and sets it raw. On CPM it is a no-op.
90 */
91
92 void
ttopen()93 ttopen ()
94 {
95 #if defined(BSD) && !defined(TERMIOS)
96 #ifdef TIOCGWINSZ
97 struct winsize ttysize;
98 #else
99 struct ttysize ttysize;
100 #endif
101
102 ioctl (0, TIOCGETP, &otermb); /* save settings */
103 ntermb = otermb; /* setup new settings */
104 ntermb.sg_flags &= ~ECHO;
105 ntermb.sg_flags |= RAW;
106 ioctl (0, TIOCSETP, &ntermb); /* and activate them */
107 kbdpoll = FALSE;
108
109 /* on all screens we are not sure of the initial position
110 of the cursor */
111 ttrow = 999;
112 ttcol = 999;
113 #ifdef TIOCGWINSZ
114 if (ioctl (0, TIOCGWINSZ, &ttysize) == 0)
115 {
116 nrow = ttysize.ws_row;
117 ncol = ttysize.ws_col;
118 #else
119 if (ioctl (0, TIOCGSIZE, &ttysize) == 0)
120 {
121 nrow = ttysize.ts_lines;
122 ncol = ttysize.ts_cols;
123 #endif /* ULTRIX */
124 }
125 else
126 {
127 nrow = NROW;
128 ncol = NCOL;
129 }
130 #else
131 #ifdef OS2
132 setmode (1, O_BINARY);
133 #else
134 #ifdef MINIX
135 ioctl (0, TIOCGETP, &otermio);
136 ntermio = otermio;
137 ntermio.sg_flags &= ~ECHO;
138 ntermio.sg_flags |= RAW;
139 ioctl (0, TIOCSETP, &ntermio);
140 ioctl (0, TIOCGETC, &tcharsorig);
141 tchars = tcharsorig;
142 tchars.t_intrc = tchars.t_quitc = tchars.t_startc =
143 tchars.t_stopc = tchars.t_eofc = tchars.t_brkc = -1;
144 ioctl (0, TIOCSETC, &tchars);
145 #else
146 #ifdef TERMIOS
147 #ifdef TIOCGWINSZ
148 struct winsize ttysize;
149 #endif
150 tcgetattr(0,&otermio);
151 ntermio.c_ispeed = otermio.c_ispeed;
152 ntermio.c_ospeed = otermio.c_ospeed;
153 #else
154 ioctl (0, TCGETA, &otermio);/* save old settings */
155 ntermio.c_line = otermio.c_line;
156 #endif
157 ntermio.c_iflag = 0; /* setup new settings */
158 ntermio.c_oflag = 0;
159 ntermio.c_cflag = otermio.c_cflag;
160 ntermio.c_lflag = 0;
161 ntermio.c_cc[VMIN] = 1;
162 ntermio.c_cc[VTIME] = 0;
163 #ifdef TERMIOS
164 tcsetattr(0,TCSANOW,&ntermio);
165 #else
166 ioctl (0, TCSETAW, &ntermio); /* and activate them */
167 #endif
168 #endif /* MINIX */
169 kbdflgs = fcntl (0, F_GETFL, 0);
170 kbdpoll = FALSE;
171 #endif /* OS2 */
172 /* on all screens we are not sure of the initial position of the cursor */
173 ttrow = 999;
174 ttcol = 999;
175 #if defined(TERMIOS) && defined(TIOCGWINSZ)
176 if (ioctl (0, TIOCGWINSZ, &ttysize) == 0)
177 {
178 nrow = ttysize.ws_row;
179 ncol = ttysize.ws_col;
180 } else
181 #endif
182 {
183 nrow = NROW;
184 ncol = NCOL;
185 }
186 #endif /* BSD */
187 }
188
189 /*
190 * This function gets called just before we go back home to the command
191 * interpreter. On VMS it puts the terminal back in a reasonable state.
192 * Another no-operation on CPM.
193 */
194 void
195 ttclose ()
196 {
197 #if defined(BSD) && !defined(TERMIOS)
198 if (ioctl (0, TIOCSETP, &otermb) == -1) /* restore terminal settings */
199 printf ("closing ioctl on dev 0 failure, error = %d\n", errno);
200 #else
201 #ifdef OS2
202 setmode (1, O_TEXT);
203 #else
204 #ifdef MINIX
205 if (ioctl (0, TIOCSETP, &otermio) == -1 ||
206 ioctl (0, TIOCSETC, &tcharsorig) == -1)
207 printf ("closing ioctl on dev 0 failure, error = %d\n", errno);
208 #else
209 #ifdef TERMIOS
210 if( tcsetattr(0,TCSANOW,&otermio) == -1)
211 #else
212 if (ioctl (0, TCSETAW, &otermio) == -1) /* restore terminal settings */
213 #endif
214 printf ("closing ioctl on dev 0 failure, error = %d\n", errno);
215 #endif /* MINIX */
216 if (fcntl (0, F_SETFL, kbdflgs) == -1)
217 printf ("closing fcntl on dev 0 failure, error = %d\n", errno);
218 #endif /* OS2 */
219 #endif /* BSD */
220 }
221
222 #ifdef OS2
223 void
224 ttraw (void)
225 {
226 #ifdef __32BIT__
227 signal (SIGINT, SIG_IGN);
228 signal (SIGBREAK, SIG_IGN);
229 #else
230 PFNSIGHANDLER oldhandler;
231 USHORT oldact;
232
233 DosSetSigHandler ((PFNSIGHANDLER) NULL, &oldhandler, &oldact,
234 SIGA_IGNORE, SIG_CTRLBREAK);
235 DosSetSigHandler ((PFNSIGHANDLER) NULL, &oldhandler, &oldact,
236 SIGA_IGNORE, SIG_CTRLC);
237 #endif
238
239 #ifndef __EMX__
240 kbst_std.cb = sizeof (kbst_std);
241 KbdGetStatus (&kbst_std, 0);
242 kbst = kbst_std;
243 kbst.fsMask &= ~(KEYBOARD_ECHO_ON | KEYBOARD_ASCII_MODE |
244 KEYBOARD_SHIFT_REPORT);
245 kbst.fsMask |= (KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE);
246 KbdSetStatus (&kbst, 0);
247 #endif
248 }
249
250 void
251 ttcooked (void)
252 {
253 #ifndef __EMX__
254 KbdSetStatus (&kbst_std, 0);
255 #endif
256 }
257
258 #endif
259
260 /*
261 * Write a character to the display. On VMS, terminal output is buffered, and
262 * we just put the characters in the big array, after checking for overflow.
263 * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
264 * MS-DOS (use the very very raw console output routine).
265 */
266
267 #ifdef OS2
268 int tty_io_size = 0;
269 char tty_io_buffer[2048];
270 #endif
271
272 int
273 ttputc (c)
274 {
275 #ifdef OS2
276 if (tty_io_size == sizeof (tty_io_buffer))
277 {
278 write (1, tty_io_buffer, tty_io_size);
279 tty_io_size = 0;
280 }
281 tty_io_buffer[tty_io_size++] = c;
282 #else
283 fputc (c, stdout);
284 #endif
285 return c;
286 }
287
288 /*
289 * Flush terminal buffer. Does real work where the terminal output is buffered
290 * up. A no-operation on systems where byte at a time terminal I/O is done.
291 */
292 void
293 ttflush ()
294 {
295 #ifdef OS2
296 if (tty_io_size)
297 {
298 write (1, tty_io_buffer, tty_io_size);
299 tty_io_size = 0;
300 }
301 #else
302 fflush (stdout);
303 #endif
304 }
305
306 /*
307 * Read a character from the terminal, performing no editing and doing no echo
308 * at all. More complex in VMS that almost anyplace else, which figures. Very
309 * simple on CPM, because the system can do exactly what you want.
310 */
311
312 #ifdef OS2
313 #ifdef __EMX__
314 static int chr = -1;
315 #endif
316 #endif
317
318 int ttgetc ()
319 {
320 #ifdef OS2
321 #ifdef __EMX__
322 if (chr != -1)
323 {
324 int c = chr;
325 chr = -1;
326 return c;
327 }
328 else
329 return _read_kbd (0, 1, 0);
330 #else
331 static int ext, scan, chr;
332 KBDKEYINFO ki;
333
334 if (ext)
335 {
336 ext = 0;
337 return scan;
338 }
339 else
340 {
341 ttflush ();
342 KbdCharIn (&ki, IO_WAIT, 0);
343
344 if (ki.chChar == 0 || ki.chChar == 0xE0)
345 {
346 ext = 1;
347 scan = ki.chScan;
348 return 0xE0;
349 }
350 else
351 return ki.chChar;
352 }
353 #endif
354 #else
355 if (kbdqp)
356 kbdqp = FALSE;
357 else
358 {
359 #ifdef BSD
360 int count;
361
362 if (kbdpoll && (ioctl (0, FIONREAD, &count), count == 0))
363 return FALSE;
364 read (0, &kbdq, 1);
365 #else
366 if (kbdpoll && fcntl (0, F_SETFL, kbdflgs) < 0)
367 return FALSE;
368 kbdpoll = FALSE;
369 while (read (0, &kbdq, 1) != 1)
370 ;
371 #endif
372 }
373 return (kbdq & 127);
374 #endif /* OS2 */
375 }
376
377 /* typahead(): Check to see if any characters are already in the
378 keyboard buffer
379 */
380 int ttkeyready ()
381 {
382 #ifdef OS2
383 #ifdef __EMX__
384 chr = _read_kbd (0, 0, 0);
385 return (chr != -1);
386 #else
387 KBDKEYINFO ki;
388
389 KbdPeek (&ki, 0);
390 return (ki.fbStatus != 0);
391 #endif
392 #else
393 if (!kbdqp)
394 {
395 #ifdef BSD
396 int count;
397
398 if (!kbdpoll && (ioctl (0, FIONREAD, &count), count == 0))
399 return FALSE;
400 kbdpoll = TRUE; /* fix in 1.13 */
401 kbdqp = TRUE;
402 #else
403 #ifdef X_MINIX
404 /* MINIX has non-blocking mode but it doesn't work !?!? */
405 return FALSE;
406 #else
407 if (!kbdpoll && fcntl (0, F_SETFL, kbdflgs | O_NDELAY) < 0)
408 return (FALSE);
409 kbdpoll = TRUE; /* fix in 1.13 */
410 kbdqp = (1 == read (0, &kbdq, 1));
411 #endif /* MINIX */
412 #endif /* BSD */
413
414 }
415 return (kbdqp);
416 #endif /* OS2 */
417 }
418
419 #endif
420