source: trunk/ncurses/tack/sysdep.c@ 2622

Last change on this file since 2622 was 2621, checked in by bird, 19 years ago

GNU ncurses 5.5

File size: 9.8 KB
Line 
1/*
2** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
3**
4** This file is part of TACK.
5**
6** TACK is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2, or (at your option)
9** any later version.
10**
11** TACK is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with TACK; see the file COPYING. If not, write to
18** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19** Boston, MA 02110-1301, USA
20*/
21/*
22 * Operating system dependent functions. We assume the POSIX API.
23 * Note: on strict-POSIX systems (including BSD/OS) the select_delay_type
24 * global has no effect.
25 */
26
27#ifdef HAVE_CONFIG_H
28#include <ncurses_cfg.h>
29#endif
30#include <signal.h> /* include before curses.h to work around glibc bug */
31
32#include <tack.h>
33
34#include <term.h>
35#include <errno.h>
36
37#if defined(__BEOS__)
38#undef false
39#undef true
40#include <OS.h>
41#endif
42
43#if HAVE_SELECT
44#if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
45#include <sys/time.h>
46#endif
47#if HAVE_SYS_SELECT_H
48#include <sys/select.h>
49#endif
50#endif
51
52MODULE_ID("$Id: sysdep.c,v 1.15 2005/09/17 19:49:16 tom Exp $")
53
54#if DECL_ERRNO
55extern int errno;
56#endif
57
58#ifdef TERMIOS
59#define PUT_TTY(fd, buf) tcsetattr(fd, TCSAFLUSH, buf)
60#else
61#define PUT_TTY(fd, buf) stty(fd, buf)
62#endif
63
64/* globals */
65int tty_frame_size; /* asynch frame size times 2 */
66unsigned tty_baud_rate; /* baud rate - bits per second */
67int not_a_tty; /* TRUE if output is not a tty (i.e. pipe) */
68int nodelay_read; /* TRUE if NDELAY is set */
69
70#ifdef TERMIOS
71#define TTY_IS_NOECHO !(new_modes.c_lflag & ECHO)
72#define TTY_IS_OUT_TRANS (new_modes.c_oflag & OPOST)
73#define TTY_IS_CHAR_MODE !(new_modes.c_lflag & ICANON)
74#define TTY_WAS_CS8 ((old_modes.c_cflag & CSIZE) == CS8)
75#define TTY_WAS_XON_XOFF (old_modes.c_iflag & (IXON|IXOFF))
76#else
77#define TTY_IS_NOECHO !(new_modes.sg_flags & (ECHO))
78#define TTY_IS_OUT_TRANS (new_modes.sg_flags & (CRMOD))
79#define TTY_IS_CHAR_MODE (new_modes.sg_flags & (RAW|CBREAK))
80#define TTY_WAS_CS8 (old_modes.sg_flags & (PASS8))
81#define TTY_WAS_XON_XOFF (old_modes.sg_flags & (TANDEM|MDMBUF|DECCTQ))
82#endif
83
84static TTY old_modes, new_modes;
85
86void catchsig(void);
87
88/*
89 * These are a sneaky way of conditionalizing bit unsets so strict-POSIX
90 * systems won't see them.
91 */
92#ifndef XCASE
93#define XCASE 0
94#endif
95#ifndef OLCUC
96#define OLCUC 0
97#endif
98#ifndef IUCLC
99#define IUCLC 0
100#endif
101#ifndef TABDLY
102#define TABDLY 0
103#endif
104#ifndef IXANY
105#define IXANY 0
106#endif
107
108void
109tty_raw(int minch GCC_UNUSED, int mask)
110{ /* set tty to raw noecho */
111 new_modes = old_modes;
112#ifdef TERMIOS
113#if HAVE_SELECT
114 new_modes.c_cc[VMIN] = 1;
115#else
116 new_modes.c_cc[VMIN] = minch;
117#endif
118 new_modes.c_cc[VTIME] = 2;
119 new_modes.c_lflag &=
120 ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK | ECHONL);
121#ifdef LOBLK
122 new_modes.c_lflag &= ~LOBLK;
123#endif
124 new_modes.c_oflag &= ~(OPOST | OLCUC | TABDLY);
125 if (mask == ALLOW_PARITY) {
126 new_modes.c_cflag &= ~(CSIZE | PARENB | HUPCL);
127 new_modes.c_cflag |= CS8;
128 }
129 new_modes.c_iflag &=
130 ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL |
131 IUCLC | IXON | IXANY | IXOFF);
132#else
133 new_modes.sg_flags |= RAW;
134#endif
135 if (not_a_tty)
136 return;
137 PUT_TTY(fileno(stdin), &new_modes);
138}
139
140void
141tty_set(void)
142{ /* set tty to special modes */
143 new_modes = old_modes;
144#ifdef TERMIOS
145 new_modes.c_cc[VMIN] = 1;
146 new_modes.c_cc[VTIME] = 1;
147 new_modes.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
148#if defined(ONLCR) && defined(OCRNL) && defined(ONLRET) && defined(OFILL)
149 new_modes.c_oflag &= ~(ONLCR | OCRNL | ONLRET | OFILL);
150#else
151 new_modes.c_oflag &= ~(OPOST);
152#endif
153 if (char_mask == ALLOW_PARITY)
154 new_modes.c_iflag &= ~ISTRIP;
155 switch (select_xon_xoff) {
156 case 0:
157 new_modes.c_iflag &= ~(IXON | IXOFF);
158 break;
159 case 1:
160#if defined(sequent) && sequent
161 /* the sequent System V emulation is broken */
162 new_modes = old_modes;
163 new_modes.c_cc[VEOL] = 6; /* control F (ACK) */
164#endif
165 new_modes.c_iflag |= IXON | IXOFF;
166 break;
167 }
168 switch (select_delay_type) {
169 case 0:
170#ifdef NLDLY
171 new_modes.c_oflag &=
172 ~(NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
173#endif /* NLDLY */
174 break;
175 case 1:
176#ifdef NLDLY
177 new_modes.c_oflag &=
178 ~(NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
179#endif /* NLDLY */
180#ifdef NL1
181 new_modes.c_oflag |= NL1 | CR2;
182#endif /* NL1 */
183 break;
184 }
185 if (!(new_modes.c_oflag & (unsigned long) ~OPOST))
186 new_modes.c_oflag &= (unsigned long) ~OPOST;
187#else
188 new_modes.sg_flags |= RAW;
189 if (not_a_tty)
190 return;
191#endif
192 PUT_TTY(fileno(stdin), &new_modes);
193}
194
195
196void
197tty_reset(void)
198{ /* reset the tty to the original modes */
199 fflush(stdout);
200 if (not_a_tty)
201 return;
202 PUT_TTY(fileno(stdin), &old_modes);
203}
204
205
206void
207tty_init(void)
208{ /* ATT terminal init */
209#if defined(F_GETFL) && defined(O_NDELAY)
210 int flags;
211
212 flags = fcntl(fileno(stdin), F_GETFL, 0);
213 nodelay_read = flags & O_NDELAY;
214#else
215 nodelay_read = FALSE;
216#endif
217 not_a_tty = FALSE;
218 if (GET_TTY(fileno(stdin), &old_modes) == -1) {
219 if (errno == ENOTTY) {
220 tty_frame_size = 20;
221 not_a_tty = TRUE;
222 return;
223 }
224 printf("tcgetattr error: %d\n", errno);
225 exit(1);
226 }
227 /* if TAB3 is set then setterm() wipes out tabs (ht) */
228 new_modes = old_modes;
229#ifdef TERMIOS
230#ifdef TABDLY
231 new_modes.c_oflag &= ~TABDLY;
232#endif /* TABDLY */
233#endif
234 if (PUT_TTY(fileno(stdin), &new_modes) == -1) {
235 printf("tcsetattr error: %d\n", errno);
236 exit(1);
237 }
238#ifdef sequent
239 /* the sequent ATT emulation is broken soooo. */
240 old_modes.c_cflag &= ~(CSIZE | CSTOPB);
241 old_modes.c_cflag |= CS7 | PARENB;
242#endif
243 catchsig();
244#ifdef TERMIOS
245 switch (old_modes.c_cflag & CSIZE) {
246#if defined(CS5) && (CS5 != 0)
247 case CS5:
248 tty_frame_size = 10;
249 break;
250#endif
251#if defined(CS6) && (CS6 != 0)
252 case CS6:
253 tty_frame_size = 12;
254 break;
255#endif
256#if defined(CS7) && (CS7 != 0)
257 case CS7:
258 tty_frame_size = 14;
259 break;
260#endif
261#if defined(CS8) && (CS8 != 0)
262 case CS8:
263 tty_frame_size = 16;
264 break;
265#endif
266 }
267 tty_frame_size += 2 +
268 ((old_modes.c_cflag & PARENB) ? 2 : 0) +
269 ((old_modes.c_cflag & CSTOPB) ? 4 : 2);
270#else
271 tty_frame_size = 6 +
272 (old_modes.sg_flags & PASS8) ? 16 : 14;
273#endif
274}
275
276/*
277** stty_query(question)
278**
279** Does the current driver settings have this property?
280*/
281int
282stty_query(int q)
283{
284 switch (q) {
285 case TTY_NOECHO:
286 return TTY_IS_NOECHO;
287 case TTY_OUT_TRANS:
288 return TTY_IS_OUT_TRANS;
289 case TTY_CHAR_MODE:
290 return TTY_IS_CHAR_MODE;
291 }
292 return (-1);
293}
294
295/*
296** initial_stty_query(question)
297**
298** Did the initial driver settings have this property?
299*/
300int
301initial_stty_query(int q)
302{
303 switch (q) {
304 case TTY_8_BIT:
305 return TTY_WAS_CS8;
306 case TTY_XON_XOFF:
307 return TTY_WAS_XON_XOFF;
308 }
309 return (-1);
310}
311
312#if HAVE_SELECT && defined(FD_ZERO)
313static int
314char_ready(void)
315{
316 int n;
317 fd_set ifds;
318 struct timeval tv;
319
320 FD_ZERO(&ifds);
321 FD_SET(fileno(stdin), &ifds);
322 tv.tv_sec = 0;
323 tv.tv_usec = 200000;
324 n = select(fileno(stdin)+1, &ifds, NULL, NULL, &tv);
325 return (n != 0);
326}
327
328#else
329#ifdef FIONREAD
330int
331char_ready(void)
332{
333 int i, j;
334
335 /* the following loop has to be tuned for each computer */
336 for (j = 0; j < 1000; j++) {
337 ioctl(fileno(stdin), FIONREAD, &i);
338 if (i)
339 return i;
340 }
341 return i;
342}
343
344#else
345#if defined(__BEOS__)
346int
347char_ready(void)
348{
349 int n = 0;
350 int howmany = ioctl(0, 'ichr', &n);
351 return (howmany >= 0 && n > 0);
352}
353#else
354#define char_ready() 1
355#endif
356#endif
357#endif
358
359/*
360** spin_flush()
361**
362** Wait for the input stream to stop.
363** Throw away all input characters.
364*/
365void
366spin_flush(void)
367{
368 unsigned char buf[64];
369
370 fflush(stdout);
371 event_start(TIME_FLUSH); /* start the timer */
372 do {
373 if (char_ready()) {
374 (void) read(fileno(stdin), &buf, sizeof(buf));
375 }
376 } while (event_time(TIME_FLUSH) < 400000);
377}
378
379/*
380** read_key(input-buffer, length-of-buffer)
381**
382** read one function key from the input stream.
383** A null character is converted to 0x80.
384*/
385void
386read_key(char *buf, int max)
387{
388 int got, ask, i, l;
389 char *s;
390
391 *buf = '\0';
392 s = buf;
393 fflush(stdout);
394 /* ATT unix may return 0 or 1, Berkeley Unix should be 1 */
395 while (read(fileno(stdin), s, 1) == 0);
396 ++s;
397 --max;
398 while (max > 0 && (ask = char_ready())) {
399 if (ask > max) {
400 ask = max;
401 }
402 if ((got = read(fileno(stdin), s, (unsigned) ask))) {
403 s += got;
404 } else {
405 break;
406 }
407 max -= got;
408 }
409 *s = '\0';
410 l = s - buf;
411 for (s = buf, i = 0; i < l; i++) {
412 if ((*s & 0x7f) == 0) {
413 /* convert nulls to 0x80 */
414 *(unsigned char *)s = 128;
415 } else {
416 /* strip high order bits (if any) */
417 *s &= char_mask;
418 }
419 }
420}
421
422
423void
424ignoresig(void)
425{
426 /* ignore signals */
427 signal(SIGINT, SIG_IGN);
428 signal(SIGHUP, SIG_IGN);
429 signal(SIGQUIT, SIG_IGN);
430 signal(SIGTERM, SIG_IGN);
431 signal(SIGALRM, SIG_IGN);
432}
433
434 /*
435 onintr( )
436
437 is the interrupt handling routine onintr turns off interrupts while doing
438 clean-up
439
440 onintr always exits fatally
441 */
442
443
444static RETSIGTYPE
445onintr(int sig GCC_UNUSED)
446{
447 ignoresig();
448 tty_reset();
449 exit(1);
450}
451
452
453 /*
454 catchsig( )
455
456 set up to field interrupts (via function onintr( )) so that if interrupted
457 we can restore the correct terminal modes
458
459 catchsig simply returns
460 */
461
462
463void
464catchsig(void)
465{
466 if ((signal(SIGINT, SIG_IGN)) == SIG_DFL)
467 signal(SIGINT, onintr);
468
469 if ((signal(SIGHUP, SIG_IGN)) == SIG_DFL)
470 signal(SIGHUP, onintr);
471
472 if ((signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
473 signal(SIGQUIT, onintr);
474
475 if ((signal(SIGTERM, SIG_IGN)) == SIG_DFL)
476 signal(SIGTERM, onintr);
477
478}
479
480/*
481** alarm_event(sig)
482**
483** Come here for an alarm event
484*/
485static void
486alarm_event(
487 int sig GCC_UNUSED)
488{
489 no_alarm_event = 0;
490}
491
492/*
493** set_alarm_clock(seconds)
494**
495** Set the alarm clock to fire in <seconds>
496*/
497void
498set_alarm_clock(
499 int seconds)
500{
501 signal(SIGALRM, alarm_event);
502 no_alarm_event = 1;
503 (void) alarm((unsigned) seconds);
504}
Note: See TracBrowser for help on using the repository browser.