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